Generalize and share mapping menu (main, status, dock) behavior.
[enjoyable.git] / Classes / NJMappingMenuController.m
diff --git a/Classes/NJMappingMenuController.m b/Classes/NJMappingMenuController.m
new file mode 100644 (file)
index 0000000..0fa6183
--- /dev/null
@@ -0,0 +1,111 @@
+//
+//  NJMappingMenuController.m
+//  Enjoyable
+//
+//  Created by Joe Wreschnig on 3/11/13.
+//
+//
+
+#import "NJMappingMenuController.h"
+
+#import "NJEvents.h"
+#import "NJMapping.h"
+
+#define MAXIMUM_MAPPINGS_IN_MENU 15
+
+@implementation NJMappingMenuController
+
+- (id)init {
+    if ((self = [super init])) {
+        NSNotificationCenter *center = NSNotificationCenter.defaultCenter;
+        [center addObserver:self
+                   selector:@selector(mappingsListDidChange:)
+                       name:NJEventMappingListChanged
+                     object:nil];
+        [center addObserver:self
+                   selector:@selector(mappingDidChange:)
+                       name:NJEventMappingChanged
+                     object:nil];
+        [center addObserver:self
+                   selector:@selector(eventTranslationActivated:)
+                       name:NJEventTranslationActivated
+                     object:nil];
+        [center addObserver:self
+                   selector:@selector(eventTranslationDeactivated:)
+                       name:NJEventTranslationDeactivated
+                     object:nil];
+    }
+    return self;
+}
+
+- (void)dealloc {
+    [NSNotificationCenter.defaultCenter removeObserver:self];
+}
+
+- (void)_mappingWasChosen:(NSMenuItem *)sender {
+    NJMapping *mapping = sender.representedObject;
+    [self.delegate mappingWasChosen:mapping];
+}
+
+- (void)_mappingListWasChosen:(NSMenuItem *)sender {
+    [self.delegate mappingListShouldOpen];
+}
+
+- (void)mappingsListDidChange:(NSNotification *)note {
+    NSArray *mappings = note.userInfo[@"mappings"];
+    NJMapping *currentMapping = note.userInfo[@"mapping"];
+    NSMenuItem *toRemove;
+    while (self.menu.numberOfItems > self.firstMappingIndex
+           && (toRemove = [self.menu itemAtIndex:self.firstMappingIndex])
+           && ([toRemove.representedObject isKindOfClass:NJMapping.class]
+               || toRemove.representedObject == self.class))
+        [self.menu removeItemAtIndex:self.firstMappingIndex];    
+    
+    int added = 0;
+    NSUInteger index = self.firstMappingIndex;
+    for (NJMapping *mapping in mappings) {
+        NSString *keyEquiv = (++added < 10 && self.hasKeyEquivalents)
+            ? @(added).stringValue
+            : @"";
+        NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:mapping.name
+                                                      action:@selector(_mappingWasChosen:)
+                                               keyEquivalent:keyEquiv];
+        item.representedObject = mapping;
+        item.state = mapping == currentMapping;
+        item.target = self;
+        [self.menu insertItem:item atIndex:index++];
+        if (added == MAXIMUM_MAPPINGS_IN_MENU
+            && mappings.count > MAXIMUM_MAPPINGS_IN_MENU + 1) {
+            NSString *msg = [NSString stringWithFormat:@"(and %lu moreā€¦)",
+                             mappings.count - MAXIMUM_MAPPINGS_IN_MENU];
+            NSMenuItem *end = [[NSMenuItem alloc] initWithTitle:msg
+                                                         action:@selector(_mappingListWasChosen:)
+                                                  keyEquivalent:@""];
+            // There must be a represented object here so the item gets
+            // removed correctly when the menus are regenerated.
+            end.representedObject = self.class;
+            end.target = self;
+            [self.menu insertItem:end atIndex:index];
+            break;
+        }
+    }
+}
+
+- (void)mappingDidChange:(NSNotification *)note {
+    NJMapping *mapping = note.userInfo[@"mapping"];
+    for (NSMenuItem *item in self.menu.itemArray)
+        if ([item.representedObject isKindOfClass:NJMapping.class])
+            item.state = mapping == item.representedObject;
+}
+
+- (void)eventTranslationActivated:(NSNotification *)note {
+    self.eventTranslationToggle.title = @"Disable";
+}
+
+- (void)eventTranslationDeactivated:(NSNotification *)note {
+    self.eventTranslationToggle.title = @"Enable";    
+}
+
+
+
+@end