source: trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEKeyEquivalents.m @ 435

Last change on this file since 435 was 431, checked in by Nicholas Riley, 13 years ago

Handle NSUserKeyEquivalents; disable conflict resolution; fix keyEquivalents invalidation crasher

File size: 7.3 KB
Line 
1//
2//  ICeCoffEEKeyEquivalents.m
3//  ICeCoffEE APE
4//
5//  Created by Nicholas Riley on Mon Jun 9 2003.
6//  Copyright (c) 2002 Nicholas Riley. All rights reserved.
7//
8
9// Original implementations of these functions are in NSString-NJRExtensions
10// and NSFont-NJRExtensions from Pester.
11
12#import <Carbon/Carbon.h>
13#import <AppKit/AppKit.h>
14
15static NSFont *themeFont(ThemeFontID fontID) {
16    NSFont *themeFont = nil;
17    Str255 pstrFontName;
18    SInt16 fontSize = 0;
19    OSStatus status;
20    // can't simulate algorithmic styles in Cocoa in any case, so here's hoping nothing will be passed back - XXX guess this should at least accommodate the bold system font, but we don't need it
21    status = GetThemeFont(fontID, smSystemScript, pstrFontName, &fontSize, NULL);
22
23    if (status == noErr) {
24        NSString *fontName = (NSString *)CFStringCreateWithPascalString(NULL, pstrFontName, CFStringGetSystemEncoding());
25        themeFont = [NSFont fontWithName: fontName size: fontSize];
26        [fontName release];
27    }
28    if (themeFont == nil) {
29        themeFont = [NSFont systemFontOfSize: fontSize == 0 ? [NSFont systemFontSize] : fontSize];
30    }
31    return themeFont;
32}
33
34static NSString *stringWithCharacter(unichar character) {
35    return [NSString stringWithCharacters: &character length: 1];
36}
37
38static unichar combiningHelpChar[] = {0x003F, 0x20DD};
39
40static NSFont *menuItemCmdKeyFont = nil;
41static NSFont *menuItemFont = nil;
42static NSFont *collisionFont = nil;
43static NSParagraphStyle *keyEquivParaStyle;
44
45static inline void initialize() {
46    if (menuItemCmdKeyFont != nil) return;
47
48    menuItemCmdKeyFont = [themeFont(kThemeMenuItemCmdKeyFont) retain];
49    menuItemFont = [themeFont(kThemeMenuItemFont) retain];
50    collisionFont = [themeFont(kThemeSmallSystemFont) retain];
51
52    NSMutableParagraphStyle *paraStyle = [[NSMutableParagraphStyle alloc] init];
53    [paraStyle setTabStops: [NSArray arrayWithObjects:
54        [[[NSTextTab alloc] initWithType: NSRightTabStopType location: 30] autorelease],
55        [[[NSTextTab alloc] initWithType: NSLeftTabStopType location: 30.01] autorelease],
56        nil]];
57    [paraStyle setLineBreakMode: NSLineBreakByClipping];
58    keyEquivParaStyle = [paraStyle copy];
59    [paraStyle release];
60}
61
62// set tabs here, for ICeCoffEE (not in Pester)
63static NSAttributedString *attributedStringWithFont(NSString *self, NSFont *font) {
64    return [[[NSAttributedString alloc] initWithString: self attributes: [NSDictionary dictionaryWithObjectsAndKeys: font, NSFontAttributeName, keyEquivParaStyle, NSParagraphStyleAttributeName, nil]] autorelease];
65}
66
67static NSString *keyEquivalentString(NSString *self) {
68    if ([self length] != 0) {
69        const char *str = [self UTF8String];
70        unichar keyChar;
71        if (str[1] != '\0') {
72            keyChar = [self characterAtIndex: 0];
73            switch (keyChar) {
74                case NSUpArrowFunctionKey: keyChar = 0x21E1; break;
75                case NSDownArrowFunctionKey: keyChar = 0x21E3; break;
76                case NSLeftArrowFunctionKey: keyChar = 0x21E0; break;
77                case NSRightArrowFunctionKey: keyChar = 0x21E2; break;
78                case NSInsertFunctionKey:
79                    return [NSString stringWithCharacters: combiningHelpChar length: 2];
80                case NSDeleteFunctionKey: keyChar = 0x2326; break;
81                case NSHomeFunctionKey: keyChar = 0x2196; break;
82                case NSEndFunctionKey: keyChar = 0x2198; break;
83                case NSPageUpFunctionKey: keyChar = 0x21DE; break;
84                case NSPageDownFunctionKey: keyChar = 0x21DF; break;
85                case NSClearLineFunctionKey: keyChar = 0x2327; break;
86                default:
87                    if (keyChar >= NSF1FunctionKey && keyChar <= NSF35FunctionKey) {
88                        return [NSString stringWithFormat: @"F%u", keyChar - NSF1FunctionKey + 1];
89                    }
90                    return [NSString stringWithFormat: @"[unknown %lX]", keyChar];
91            }
92        } else if (str[0] >= 'A' && str[0] <= 'Z') {
93            return self;
94        } else if (str[0] >= 'a' && str[0] <= 'z') return [self uppercaseString];
95        else switch (str[0]) {
96            case '\t': keyChar = 0x21e5; break;
97            case '\r': keyChar = 0x21a9; break;
98            case '\e': keyChar = 0x238b; break;
99            case ' ': keyChar = 0x2423; break;
100            case 0x7f: keyChar = 0x232b; break; // delete
101            case 0x03: keyChar = 0x2324; break; // enter
102            case 0x19: keyChar = 0x21e4; break; // backtab
103            case 0: return @"";
104                // case '': keyChar = 0x; break;
105            default: return self; // return [NSString stringWithFormat: @"[huh? %x]", (int)str[0]];
106        }
107            return stringWithCharacter(keyChar);
108    }
109    return self;
110}
111
112NSAttributedString *ICCF_KeyEquivalentAttributedStringWithModifierFlags(NSString *self, unsigned int modifierFlags, unsigned count) {
113    initialize();
114    NSString *keyEquivalentStringNoMask = keyEquivalentString(self);
115    // use tabs here, for ICeCoffEE (not in Pester, at least without better subclassing)
116    NSAttributedString *keyEquivalentAttributedString =
117        attributedStringWithFont(
118          [NSString stringWithFormat: @"\t%@%@%@%@\t%@",
119            (modifierFlags & NSControlKeyMask) ? stringWithCharacter(kControlUnicode) : @"",
120            (modifierFlags & NSAlternateKeyMask) ? stringWithCharacter(kOptionUnicode) : @"",
121            (modifierFlags & NSShiftKeyMask) ? stringWithCharacter(kShiftUnicode) : @"",
122            (modifierFlags & NSCommandKeyMask) ? stringWithCharacter(kCommandUnicode) : @"",
123            keyEquivalentStringNoMask], menuItemCmdKeyFont);
124    unsigned noMaskLength = [keyEquivalentStringNoMask length];
125    if (noMaskLength > 3 || // Fxx
126        (noMaskLength == 1 && [keyEquivalentStringNoMask characterAtIndex: 0] <= 0x7F)) {
127        NSMutableAttributedString *astr = [keyEquivalentAttributedString mutableCopy];
128        [astr setAttributes: [NSDictionary dictionaryWithObject: menuItemFont forKey: NSFontAttributeName] range: NSMakeRange([astr length] - noMaskLength, noMaskLength)];
129        keyEquivalentAttributedString = [[astr copy] autorelease];
130        [astr release];
131    }
132    if (count > 1) {
133        NSMutableAttributedString *astr = [keyEquivalentAttributedString mutableCopy];
134        [astr appendAttributedString: [[[NSAttributedString alloc]
135            initWithString: [NSString stringWithFormat: @" (%u)", count]
136                attributes: [NSDictionary dictionaryWithObjectsAndKeys: collisionFont, NSFontAttributeName, [NSColor redColor], NSForegroundColorAttributeName, nil]] autorelease]];
137        keyEquivalentAttributedString = [[astr copy] autorelease];
138        [astr release];
139    }
140    return keyEquivalentAttributedString;
141}
142
143// converts NSUserKeyEquivalents prefixes into modifier flags
144NSAttributedString *ICCF_KeyEquivalentAttributedString(NSString *self, unsigned count) {
145    unsigned modifierFlags = 0;
146    int i;
147    for (i = 0 ; i < [self length] - 1; i++) {
148        switch ([self characterAtIndex: i]) {
149            case '@': modifierFlags |= NSCommandKeyMask; break;
150            case '~': modifierFlags |= NSAlternateKeyMask; break;
151            case '^': modifierFlags |= NSControlKeyMask; break;
152            case '$': modifierFlags |= NSShiftKeyMask; break;
153            default:
154                return nil;
155        }
156    }
157    return ICCF_KeyEquivalentAttributedStringWithModifierFlags([self substringFromIndex: i], modifierFlags, count);
158}
159
Note: See TracBrowser for help on using the repository browser.