Added more to MenuController
[MenuTunes.git] / MenuController.m
1 //
2 //  MenuController.m
3 //  MenuTunes
4 //
5 //  Created by Joseph Spiros on Wed Apr 30 2003.
6 //  Copyright (c) 2003 iThink Software. All rights reserved.
7 //
8
9 #import "MenuController.h"
10 #import "NewMainController.h"
11
12 @interface MenuController (SubmenuMethods)
13 - (NSMenu *)ratingMenu;
14 - (NSMenu *)upcomingSongsMenu;
15 - (NSMenu *)playlistsMenu;
16 - (NSMenu *)eqMenu;
17 @end
18
19 @implementation MenuController
20
21 - (id)init
22 {
23     if ( (self = [super init]) ) {
24         _menuLayout = [[NSMutableArray alloc] initWithCapacity:0];
25     }
26     return self;
27 }
28
29 - (NSMenu *)menu
30 {
31     NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
32     NSArray *menuArray = [[NSUserDefaults standardUserDefaults] arrayForKey:@"menu"];
33     NSEnumerator *enumerator = [menuArray objectEnumerator];
34     NSString *nextObject;
35     NSMenuItem *tempItem;
36     
37     //Get the current playlist, track index, etc.
38     currentRemote = [[MainController sharedController] currentRemote];
39     _currentPlaylist = [currentRemote currentPlaylistIndex];
40     _currentTrack = [currentRemote currentSongIndex];
41     _playingRadio = ([currentRemote currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist);
42     
43     //create our menu
44     while ( (nextObject = [enumerator nextObject]) ) {
45         //Main menu items
46         if ([nextObject isEqualToString:@"Play/Pause"]) {
47             tempItem = [menu addItemWithTitle:@"Play"
48                     action:@selector(performMainMenuAction:)
49                     keyEquivalent:@""];
50             [tempItem setTag:MTMenuPlayPauseItem];
51             [tempItem setTarget:self];
52             
53             switch ([currentRemote playerPlayingState]) {
54                 case ITMTRemotePlayerPlaying:
55                     [tempItem setTitle:@"Pause"];
56                 break;
57                 case ITMTRemotePlayerRewinding:
58                 case ITMTRemotePlayerForwarding:
59                     [tempItem setTitle:@"Resume"];
60                 break;
61                 default:
62                 break;
63             }
64         } else if ([nextObject isEqualToString:@"Next Track"]) {
65             tempItem = [menu addItemWithTitle:@"Next Track"
66                     action:@selector(performMainMenuAction:)
67                     keyEquivalent:@""];
68             if (_currentPlaylist) {
69                 [tempItem setTag:MTMenuNextTrackItem];
70                 [tempItem setTarget:self];
71             }
72         } else if ([nextObject isEqualToString:@"Previous Track"]) {
73             tempItem = [menu addItemWithTitle:@"Previous Track"
74                     action:@selector(performMainMenuAction:)
75                     keyEquivalent:@""];
76             if (_currentPlaylist) {
77                 [tempItem setTag:MTMenuPreviousTrackItem];
78                 [tempItem setTarget:self];
79             }
80         } else if ([nextObject isEqualToString:@"Fast Forward"]) {
81             tempItem = [menu addItemWithTitle:@"Fast Forward"
82                     action:@selector(performMainMenuAction:)
83                     keyEquivalent:@""];
84             if (_currentPlaylist) {
85                 [tempItem setTag:MTMenuFastForwardItem];
86                 [tempItem setTarget:self];
87             }
88         } else if ([nextObject isEqualToString:@"Rewind"]) {
89             tempItem = [menu addItemWithTitle:@"Rewind"
90                     action:@selector(performMainMenuAction:)
91                     keyEquivalent:@""];
92             if (_currentPlaylist) {
93                 [tempItem setTag:MTMenuRewindItem];
94                 [tempItem setTarget:self];
95             }
96         } else if ([nextObject isEqualToString:@"Preferences"]) {
97             tempItem = [menu addItemWithTitle:@"Preferences..."
98                     action:@selector(performMainMenuAction:)
99                     keyEquivalent:@""];
100             [tempItem setTag:MTMenuPreferencesItem];
101             [tempItem setTarget:self];
102         } else if ([nextObject isEqualToString:@"Quit"]) {
103             tempItem = [menu addItemWithTitle:@"Quit"
104                     action:@selector(performMainMenuAction:)
105                     keyEquivalent:@""];
106             [tempItem setTag:MTMenuQuitItem];
107             [tempItem setTarget:self];
108         } else if ([nextObject isEqualToString:@"Current Track Info"]) {
109             if (_currentPlaylist) {
110                 NSString *title = [currentRemote currentSongTitle];
111                 
112                 [menu addItemWithTitle:@"Now Playing" action:NULL keyEquivalent:@""];
113                 
114                 if ([title length] > 0) {
115                     [menu addItemWithTitle:[NSString stringWithFormat:@"         %@", title] action:nil keyEquivalent:@""];
116                 }
117                 //Gotta add artist, album, track, time, etc, blah, blah, blah...
118             } else {
119                 [menu addItemWithTitle:@"No Song" action:NULL keyEquivalent:@""];
120             }
121         } else if ([nextObject isEqualToString:@"<separator>"]) {
122             [menu addItem:[NSMenuItem separatorItem]];
123         //Submenu items
124         } else if ([nextObject isEqualToString:@"Song Rating"]) {
125             tempItem = [menu addItemWithTitle:@"Song Rating"
126                     action:nil
127                     keyEquivalent:@""];
128             [tempItem setSubmenu:[self ratingMenu]];
129         } else if ([nextObject isEqualToString:@"Upcoming Songs"]) {
130             tempItem = [menu addItemWithTitle:@"Upcoming Songs"
131                     action:nil
132                     keyEquivalent:@""];
133             [tempItem setSubmenu:[self upcomingSongsMenu]];
134         } else if ([nextObject isEqualToString:@"Playlists"]) {
135             tempItem = [menu addItemWithTitle:@"Playlists"
136                     action:nil
137                     keyEquivalent:@""];
138             [tempItem setSubmenu:[self playlistsMenu]];
139         } else if ([nextObject isEqualToString:@"EQ Presets"]) {
140             tempItem = [menu addItemWithTitle:@"EQ Presets"
141                     action:nil
142                     keyEquivalent:@""];
143             [tempItem setSubmenu:[self eqMenu]];
144         }
145     }
146     
147     [_currentMenu release];
148     _currentMenu = menu;
149     return _currentMenu;
150 }
151
152 - (NSMenu *)menuForNoPlayer
153 {
154     NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
155     NSMenuItem *tempItem;
156     tempItem = [menu addItemWithTitle:[NSString stringWithFormat:@"Open %@", [[[MainController sharedController] currentRemote] playerSimpleName]] action:@selector(performMainMenuAction:) keyEquivalent:@""];
157     [tempItem setTag:MTMenuShowPlayerItem];
158     [tempItem setTarget:self];
159     [menu addItem:[NSMenuItem separatorItem]];
160     tempItem = [menu addItemWithTitle:@"Preferences" action:@selector(performMainMenuAction:) keyEquivalent:@""];
161     [tempItem setTag:MTMenuPreferencesItem];
162     [tempItem setTarget:self];
163     tempItem = [menu addItemWithTitle:@"Quit" action:@selector(performMainMenuAction:) keyEquivalent:@""];
164     [tempItem setTag:MTMenuQuitItem];
165     [tempItem setTarget:self];
166     return [menu autorelease];
167 }
168
169 - (NSMenu *)ratingMenu
170 {
171     NSMenu *ratingMenu = [[NSMenu alloc] initWithTitle:@""];
172     return [ratingMenu autorelease];
173 }
174
175 - (NSMenu *)upcomingSongsMenu
176 {
177     NSMenu *upcomingSongsMenu = [[NSMenu alloc] initWithTitle:@""];
178     int numSongs = [currentRemote numberOfSongsInPlaylistAtIndex:_currentPlaylist];
179     int numSongsInAdvance = [[NSUserDefaults standardUserDefaults] integerForKey:@"SongsInAdvance"];
180     
181     if (_currentPlaylist && !_playingRadio) {
182         if (numSongs > 0) {
183             int i;
184             
185             for (i = _currentTrack + 1; i <= _currentTrack + numSongsInAdvance; i++) {
186                 if (i <= numSongs) {
187                     NSString *curSong = [currentRemote songTitleAtIndex:i];
188                     NSMenuItem *songItem;
189                     songItem = [upcomingSongsMenu addItemWithTitle:curSong action:@selector(performUpcomingSongsMenuAction:) keyEquivalent:@""];
190                     [songItem setTag:i];
191                     [songItem setTarget:self];
192                 } else {
193                     break;
194                 }
195             }
196         }
197     }
198     return [upcomingSongsMenu autorelease];
199 }
200
201 - (NSMenu *)playlistsMenu
202 {
203     NSMenu *playlistsMenu = [[NSMenu alloc] initWithTitle:@""];
204     return [playlistsMenu autorelease];
205 }
206
207 - (NSMenu *)eqMenu
208 {
209     NSMenu *eqMenu = [[NSMenu alloc] initWithTitle:@""];
210     return [eqMenu autorelease];
211 }
212
213 - (void)performMainMenuAction:(id)sender
214 {
215     switch ( [sender tag] )
216     {
217         case MTMenuPlayPauseItem:
218             NSLog(@"MenuController: Play/Pause");
219             [[MainController sharedController] playPause];
220             //We're gonna have to change the Play menu item to Pause here too.
221             break;
222         case MTMenuFastForwardItem:
223             NSLog(@"MenuController: Fast Forward");
224             [[MainController sharedController] fastForward];
225             //make sure play/pause item says sane through this
226             break;
227         case MTMenuRewindItem:
228             NSLog(@"MenuController: Rewind");
229             [[MainController sharedController] rewind];
230             //make sure play/pause item says sane through this
231             break;
232         case MTMenuPreviousTrackItem:
233             NSLog(@"MenuController: Previous Track");
234             [[MainController sharedController] prevSong];
235             break;
236         case MTMenuNextTrackItem:
237             NSLog(@"MenuController: Next Track");
238             [[MainController sharedController] nextSong];
239             break;
240         case MTMenuShowPlayerItem:
241             NSLog(@"MainController: Show Main Interface");
242             [[MainController sharedController] showPlayer];
243             break;
244         case MTMenuPreferencesItem:
245             NSLog(@"MenuController: Preferences...");
246             [[MainController sharedController] showPreferences];
247             break;
248         case MTMenuQuitItem:
249             NSLog(@"MenuController: Quit");
250             [[MainController sharedController] quitMenuTunes];
251             break;
252         default:
253             NSLog(@"MenuController: Unimplemented Menu Item OR Child-bearing Menu Item");
254             break;
255     }
256 }
257
258 - (void)performRatingMenuAction:(id)sender
259 {
260     [[MainController sharedController] selectSongRating:[sender tag]];
261 }
262
263 - (void)performPlaylistMenuAction:(id)sender
264 {
265     [[MainController sharedController] selectPlaylistAtIndex:[sender tag]];
266 }
267
268 - (void)performEqualizerMenuAction:(id)sender
269 {
270     [[MainController sharedController] selectEQPresetAtIndex:[sender tag]];
271 }
272
273 - (void)performUpcomingSongsMenuAction:(id)sender
274 {
275     [[MainController sharedController] selectSongAtIndex:[sender tag]];
276 }
277
278 - (void)updateMenu
279 {
280     
281     [_currentMenu update];
282 }
283
284 - (BOOL)validateMenuItem:(id <NSMenuItem>)menuItem
285 {
286     return YES;
287 }
288
289 - (NSString *)systemUIColor
290 {
291     NSDictionary *tmpDict;
292     NSNumber *tmpNumber;
293     if ( (tmpDict = [NSDictionary dictionaryWithContentsOfFile:[@"~/Library/Preferences/.GlobalPreferences.plist" stringByExpandingTildeInPath]]) ) {
294         if ( (tmpNumber = [tmpDict objectForKey:@"AppleAquaColorVariant"]) ) {
295             if ( ([tmpNumber intValue] == 1) ) {
296                 return @"Aqua";
297             } else {
298                 return @"Graphite";
299             }
300         } else {
301             return @"Aqua";
302         }
303     } else {
304         return @"Aqua";
305     }
306 }
307
308 - (void)setKeyEquivalentForCode:(short)code andModifiers:(long)modifiers
309         onItem:(NSMenuItem *)item
310 {
311     unichar charcode = 'a';
312     int i;
313     long cocoaModifiers = 0;
314     static long carbonToCocoa[6][2] = 
315     {
316         { cmdKey, NSCommandKeyMask },
317         { optionKey, NSAlternateKeyMask },
318         { controlKey, NSControlKeyMask },
319         { shiftKey, NSShiftKeyMask },
320     };
321     
322     for (i = 0; i < 6; i++) {
323         if (modifiers & carbonToCocoa[i][0]) {
324             cocoaModifiers += carbonToCocoa[i][1];
325         }
326     }
327     [item setKeyEquivalentModifierMask:cocoaModifiers];
328     
329     //Missing key combos for some keys. Must find them later.
330     switch (code)
331     {
332         case 36:
333             charcode = '\r';
334         break;
335         
336         case 48:
337             charcode = '\t';
338         break;
339         
340         //Space -- ARGH!
341         case 49:
342         {
343             // Haven't tested this, though it should work.
344             // This doesn't work. :'(
345             unichar buffer;
346             [[NSString stringWithString:@"Space"] getCharacters:&buffer];
347             charcode = buffer;
348             /*MenuRef menuRef = _NSGetCarbonMenu([item menu]);
349             NSLog(@"%@", menuRef);
350             SetMenuItemCommandKey(menuRef, 0, NO, 49);
351             SetMenuItemModifiers(menuRef, 0, kMenuNoCommandModifier);
352             SetMenuItemKeyGlyph(menuRef, 0, kMenuBlankGlyph);
353             charcode = 'b';*/
354             
355         }
356         break;
357         
358         case 51:
359             charcode = NSDeleteFunctionKey;
360         break;
361         
362         case 53:
363             charcode = '\e';
364         break;
365         
366         case 71:
367             charcode = '\e';
368         break;
369         
370         case 76:
371             charcode = '\r';
372         break;
373         
374         case 96:
375             charcode = NSF5FunctionKey;
376         break;
377         
378         case 97:
379             charcode = NSF6FunctionKey;
380         break;
381         
382         case 98:
383             charcode = NSF7FunctionKey;
384         break;
385         
386         case 99:
387             charcode = NSF3FunctionKey;
388         break;
389         
390         case 100:
391             charcode = NSF8FunctionKey;
392         break;
393         
394         case 101:
395             charcode = NSF9FunctionKey;
396         break;
397         
398         case 103:
399             charcode = NSF11FunctionKey;
400         break;
401         
402         case 105:
403             charcode = NSF3FunctionKey;
404         break;
405         
406         case 107:
407             charcode = NSF14FunctionKey;
408         break;
409         
410         case 109:
411             charcode = NSF10FunctionKey;
412         break;
413         
414         case 111:
415             charcode = NSF12FunctionKey;
416         break;
417         
418         case 113:
419             charcode = NSF13FunctionKey;
420         break;
421         
422         case 114:
423             charcode = NSInsertFunctionKey;
424         break;
425         
426         case 115:
427             charcode = NSHomeFunctionKey;
428         break;
429         
430         case 116:
431             charcode = NSPageUpFunctionKey;
432         break;
433         
434         case 117:
435             charcode = NSDeleteFunctionKey;
436         break;
437         
438         case 118:
439             charcode = NSF4FunctionKey;
440         break;
441         
442         case 119:
443             charcode = NSEndFunctionKey;
444         break;
445         
446         case 120:
447             charcode = NSF2FunctionKey;
448         break;
449         
450         case 121:
451             charcode = NSPageDownFunctionKey;
452         break;
453         
454         case 122:
455             charcode = NSF1FunctionKey;
456         break;
457         
458         case 123:
459             charcode = NSLeftArrowFunctionKey;
460         break;
461         
462         case 124:
463             charcode = NSRightArrowFunctionKey;
464         break;
465         
466         case 125:
467             charcode = NSDownArrowFunctionKey;
468         break;
469         
470         case 126:
471             charcode = NSUpArrowFunctionKey;
472         break;
473     }
474     
475     if (charcode == 'a') {
476         unsigned long state;
477         long keyTrans;
478         char charCode;
479         Ptr kchr;
480         state = 0;
481         kchr = (Ptr) GetScriptVariable(smCurrentScript, smKCHRCache);
482         keyTrans = KeyTranslate(kchr, code, &state);
483         charCode = keyTrans;
484         [item setKeyEquivalent:[NSString stringWithCString:&charCode length:1]];
485     } else if (charcode != 'b') {
486         [item setKeyEquivalent:[NSString stringWithCharacters:&charcode length:1]];
487     }
488 }
489
490 @end