// // ICeCoffEEKeyEquivalents.m // ICeCoffEE APE // // Created by Nicholas Riley on Mon Jun 9 2003. // Copyright (c) 2002 Nicholas Riley. All rights reserved. // // Original implementations of these functions are in NSString-NJRExtensions // and NSFont-NJRExtensions from Pester. #import #import static NSFont *themeFont(ThemeFontID fontID) { NSFont *themeFont = nil; Str255 pstrFontName; SInt16 fontSize = 0; OSStatus status; // 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 status = GetThemeFont(fontID, smSystemScript, pstrFontName, &fontSize, NULL); if (status == noErr) { NSString *fontName = (NSString *)CFStringCreateWithPascalString(NULL, pstrFontName, CFStringGetSystemEncoding()); themeFont = [NSFont fontWithName: fontName size: fontSize]; [fontName release]; } if (themeFont == nil) { themeFont = [NSFont systemFontOfSize: fontSize == 0 ? [NSFont systemFontSize] : fontSize]; } return themeFont; } static NSString *stringWithCharacter(unichar character) { return [NSString stringWithCharacters: &character length: 1]; } static unichar combiningHelpChar[] = {0x003F, 0x20DD}; static NSFont *menuItemCmdKeyFont = nil; static NSFont *menuItemFont = nil; static NSFont *collisionFont = nil; static NSParagraphStyle *keyEquivParaStyle; static inline void initialize() { if (menuItemCmdKeyFont != nil) return; menuItemCmdKeyFont = [themeFont(kThemeMenuItemCmdKeyFont) retain]; menuItemFont = [themeFont(kThemeMenuItemFont) retain]; collisionFont = [themeFont(kThemeSmallSystemFont) retain]; NSMutableParagraphStyle *paraStyle = [[NSMutableParagraphStyle alloc] init]; [paraStyle setTabStops: [NSArray arrayWithObjects: [[[NSTextTab alloc] initWithType: NSRightTabStopType location: 30] autorelease], [[[NSTextTab alloc] initWithType: NSLeftTabStopType location: 30.01] autorelease], nil]]; [paraStyle setLineBreakMode: NSLineBreakByClipping]; keyEquivParaStyle = [paraStyle copy]; [paraStyle release]; } // set tabs here, for ICeCoffEE (not in Pester) static NSAttributedString *attributedStringWithFont(NSString *self, NSFont *font) { return [[[NSAttributedString alloc] initWithString: self attributes: [NSDictionary dictionaryWithObjectsAndKeys: font, NSFontAttributeName, keyEquivParaStyle, NSParagraphStyleAttributeName, nil]] autorelease]; } static NSString *keyEquivalentString(NSString *self) { if ([self length] != 0) { const char *str = [self UTF8String]; unichar keyChar; if (str[1] != '\0') { keyChar = [self characterAtIndex: 0]; switch (keyChar) { case NSUpArrowFunctionKey: keyChar = 0x21E1; break; case NSDownArrowFunctionKey: keyChar = 0x21E3; break; case NSLeftArrowFunctionKey: keyChar = 0x21E0; break; case NSRightArrowFunctionKey: keyChar = 0x21E2; break; case NSInsertFunctionKey: return [NSString stringWithCharacters: combiningHelpChar length: 2]; case NSDeleteFunctionKey: keyChar = 0x2326; break; case NSHomeFunctionKey: keyChar = 0x2196; break; case NSEndFunctionKey: keyChar = 0x2198; break; case NSPageUpFunctionKey: keyChar = 0x21DE; break; case NSPageDownFunctionKey: keyChar = 0x21DF; break; case NSClearLineFunctionKey: keyChar = 0x2327; break; default: if (keyChar >= NSF1FunctionKey && keyChar <= NSF35FunctionKey) { return [NSString stringWithFormat: @"F%u", keyChar - NSF1FunctionKey + 1]; } return [NSString stringWithFormat: @"[unknown %lX]", keyChar]; } } else if (str[0] >= 'A' && str[0] <= 'Z') { return self; } else if (str[0] >= 'a' && str[0] <= 'z') return [self uppercaseString]; else switch (str[0]) { case '\t': keyChar = 0x21e5; break; case '\r': keyChar = 0x21a9; break; case '\e': keyChar = 0x238b; break; case ' ': keyChar = 0x2423; break; case 0x7f: keyChar = 0x232b; break; // delete case 0x03: keyChar = 0x2324; break; // enter case 0x19: keyChar = 0x21e4; break; // backtab case 0: return @""; // case '': keyChar = 0x; break; default: return self; // return [NSString stringWithFormat: @"[huh? %x]", (int)str[0]]; } return stringWithCharacter(keyChar); } return self; } NSAttributedString *ICCF_KeyEquivalentAttributedStringWithModifierFlags(NSString *self, unsigned int modifierFlags, unsigned count) { initialize(); NSString *keyEquivalentStringNoMask = keyEquivalentString(self); // use tabs here, for ICeCoffEE (not in Pester, at least without better subclassing) NSAttributedString *keyEquivalentAttributedString = attributedStringWithFont( [NSString stringWithFormat: @"\t%@%@%@%@\t%@", (modifierFlags & NSControlKeyMask) ? stringWithCharacter(kControlUnicode) : @"", (modifierFlags & NSAlternateKeyMask) ? stringWithCharacter(kOptionUnicode) : @"", (modifierFlags & NSShiftKeyMask) ? stringWithCharacter(kShiftUnicode) : @"", (modifierFlags & NSCommandKeyMask) ? stringWithCharacter(kCommandUnicode) : @"", keyEquivalentStringNoMask], menuItemCmdKeyFont); unsigned noMaskLength = [keyEquivalentStringNoMask length]; if (noMaskLength > 3 || // Fxx (noMaskLength == 1 && [keyEquivalentStringNoMask characterAtIndex: 0] <= 0x7F)) { NSMutableAttributedString *astr = [keyEquivalentAttributedString mutableCopy]; [astr setAttributes: [NSDictionary dictionaryWithObject: menuItemFont forKey: NSFontAttributeName] range: NSMakeRange([astr length] - noMaskLength, noMaskLength)]; keyEquivalentAttributedString = [[astr copy] autorelease]; [astr release]; } if (count > 1) { NSMutableAttributedString *astr = [keyEquivalentAttributedString mutableCopy]; [astr appendAttributedString: [[[NSAttributedString alloc] initWithString: [NSString stringWithFormat: @" (%u)", count] attributes: [NSDictionary dictionaryWithObjectsAndKeys: collisionFont, NSFontAttributeName, [NSColor redColor], NSForegroundColorAttributeName, nil]] autorelease]]; keyEquivalentAttributedString = [[astr copy] autorelease]; [astr release]; } return keyEquivalentAttributedString; }