1 /* Copyright (c) 2006-2007 Christopher J. W. Lloyd
3 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
9 #import <AppKit/NSFontManager.h>
10 #import <AppKit/NSFontPanel.h>
11 #import <AppKit/NSFont.h>
12 #import <AppKit/NSFontFamily.h>
13 #import <AppKit/NSFontTypeface.h>
14 #import <AppKit/NSNibLoading.h>
15 #import <AppKit/NSApplication.h>
16 #import <AppKit/NSMenuItem.h>
17 #import <AppKit/NSMenu.h>
18 #import <AppKit/NSRaise.h>
20 @implementation NSFontManager
22 static Class _fontManagerFactory;
23 static Class _fontPanelFactory;
25 +(NSFontManager *)sharedFontManager {
26 NSString *name=@"NSFontManager";
28 if(_fontManagerFactory!=Nil)
29 name=NSStringFromClass(_fontManagerFactory);
31 return NSThreadSharedInstance(name);
34 +(void)setFontManagerFactory:(Class)value {
35 _fontManagerFactory=value;
38 +(void)setFontPanelFactory:(Class)value {
39 _fontPanelFactory=value;
44 _action=@selector(changeFont:);
45 _selectedFont=[[NSFont userFontOfSize:0] retain];
58 -(void)setDelegate:delegate {
62 -(void)setAction:(SEL)value {
66 - (NSFontAction)currentFontAction
68 return _currentFontAction;
71 -(NSArray *)collectionNames {
72 NSUnimplementedMethod();
76 -(BOOL)addCollection:(NSString *)name options:(int)options {
77 NSUnimplementedMethod();
81 -(void)addFontDescriptors:(NSArray *)descriptors toCollection:(NSString *)name {
82 NSUnimplementedMethod();
85 -(BOOL)removeCollection:(NSString *)name {
86 NSUnimplementedMethod();
90 -(NSArray *)fontDescriptorsInCollection:(NSString *)name {
91 NSUnimplementedMethod();
95 -(NSArray *)availableFonts {
96 NSMutableArray *result=[NSMutableArray array];
97 NSArray *families=[NSFontFamily allFontFamilyNames];
98 int i,count=[families count];
100 for(i=0;i<count;i++){
101 NSString *familyName=[families objectAtIndex:i];
102 NSFontFamily *family=[NSFontFamily fontFamilyWithName:familyName];
103 NSArray *typefaces=[family typefaces];
104 int t,tcount=[typefaces count];
106 for(t=0;t<tcount;t++){
107 NSFontTypeface *typeface=[typefaces objectAtIndex:t];
108 NSString *name=[typeface name];
110 [result addObject:name];
117 -(NSArray *)availableFontFamilies {
118 NSArray *families=[NSFontFamily allFontFamilyNames];
120 if(![_delegate respondsToSelector:@selector(fontManager:willIncludeFont:)])
123 NSMutableArray *result=[NSMutableArray array];
124 int i,count=[families count];
126 for(i=0;i<count;i++){
127 NSString *familyName=[families objectAtIndex:i];
128 NSFontFamily *family=[NSFontFamily fontFamilyWithName:familyName];
129 NSArray *typefaces=[family typefaces];
130 int t,tcount=[typefaces count];
132 for(t=0;t<tcount;t++){
133 NSFontTypeface *typeface=[typefaces objectAtIndex:t];
134 NSString *name=[typeface name];
136 if([_delegate fontManager:self willIncludeFont:name]){
137 [result addObject:familyName];
147 -(NSArray *)availableMembersOfFontFamily:(NSString *)familyName {
148 NSMutableArray *result=[NSMutableArray array];
149 NSFontFamily *family=[NSFontFamily fontFamilyWithName:familyName];
150 NSArray *typefaces=[family typefaces];
151 int i,count=[typefaces count];
153 for(i=0;i<count;i++){
154 NSFontTypeface *typeface=[typefaces objectAtIndex:i];
155 NSString *name=[typeface name];
156 NSString *traitName=[typeface traitName];
158 // Callers expect an array of four objects
159 [result addObject:[NSArray arrayWithObjects:name,traitName, [NSNumber numberWithInt: 0], [NSNumber numberWithInt: 0], nil]];
165 -(NSArray *)availableFontNamesMatchingFontDescriptor:(NSFontDescriptor *)descriptor {
166 NSUnimplementedMethod();
170 -(NSArray *)availableFontNamesWithTraits:(NSFontTraitMask)traits {
171 NSUnimplementedMethod();
175 -(BOOL)fontNamed:(NSString *)name hasTraits:(NSFontTraitMask)traits {
176 NSFont* font = [NSFont fontWithName: name size: 12];
177 NSFontTraitMask fontTraits=[self traitsOfFont:font];
178 return (traits & fontTraits) == traits;
181 -(NSFont *)fontWithFamily:(NSString *)familyName traits:(NSFontTraitMask)traits weight:(int)weight size:(float)size {
182 // Note : weight is ignored
184 NSFontFamily *family=[NSFontFamily fontFamilyWithName:familyName];
185 NSArray *typefaces=[family typefaces];
186 int i,count=[typefaces count];
187 NSString *fontName=nil;
189 for(i=0;i<count;i++){
190 NSFontTypeface *typeface=[typefaces objectAtIndex:i];
191 NSFontTraitMask checkTraits=[typeface traits];
193 if(((traits&NSItalicFontMask)==(checkTraits&NSItalicFontMask)) &&
194 ((traits&NSBoldFontMask)==(checkTraits&NSBoldFontMask))) {
195 fontName = [typeface name];
200 if (fontName == nil) {
202 if ([typefaces count] > 0) {
203 NSFontTypeface *typeface=[typefaces objectAtIndex:0];
204 fontName = [typeface name];
209 if (fontName != nil) {
210 font = [NSFont fontWithName:fontName size:size];
212 NSLog(@"unable to match any font in faces '%@' of family '%@' with traits mask: %d", typefaces, familyName, traits);
218 -(int)weightOfFont:(NSFont *)font {
219 return 5; // default to the normal weight
222 -(NSFontTraitMask)traitsOfFont:(NSFont *)font {
223 NSFontTypeface *typeface=[NSFontFamily fontTypefaceWithName:[font fontName]];
225 return [typeface traits];
228 -(NSString *)localizedNameForFamily:(NSString *)family face:(NSString *)face {
232 return [NSString stringWithFormat: @"%@ %@", family, face];
235 -(void)setFontPanel:(NSFontPanel *)panel {
236 panel=[panel retain];
241 -(NSFontPanel *)fontPanel:(BOOL)create {
242 if(_panel==nil && create){
243 [NSBundle loadNibNamed:@"NSFontPanel" owner:self];
246 if(![_panel setFrameUsingName:@"NSFontPanel"]) {
249 [_panel setFrameAutosaveName:@"NSFontPanel"];
252 [_panel setPanelFont:_selectedFont isMultiple:_isMultiple];
257 return [NSApp sendAction:_action to:nil from:[NSFontManager sharedFontManager]];
261 NSUnimplementedMethod();
269 -(NSFont *)selectedFont {
270 return _selectedFont;
273 -(void)_configureMenu:(NSMenu *)menu forFont:(NSFont *)font {
274 NSArray *items=[menu itemArray];
275 int i,count=[items count];
277 for(i=0;i<count;i++){
278 NSMenuItem *item=[items objectAtIndex:i];
280 if([item hasSubmenu])
281 [self _configureMenu:[item submenu] forFont:font];
282 else if(sel_isEqual([item action],@selector(addFontTrait:)) && [item target]==self){
283 unsigned tag=[item tag];
284 NSFontTraitMask traits=[self traitsOfFont:font];
286 if(tag&(NSItalicFontMask|NSUnitalicFontMask)){
287 if(traits&NSItalicFontMask){
288 [item setTag:NSUnitalicFontMask];
289 [item setTitle: NSLocalizedStringFromTableInBundle(@"Unitalic", nil, [NSBundle bundleForClass: [NSFontManager class]], @"Remove the italic font trait")];
292 [item setTag:NSItalicFontMask];
293 [item setTitle: NSLocalizedStringFromTableInBundle(@"Italic", nil, [NSBundle bundleForClass: [NSFontManager class]], @"Add the italic font trait")];
296 if(tag&(NSBoldFontMask|NSUnboldFontMask)){
297 if(traits& NSBoldFontMask){
298 [item setTag:NSUnboldFontMask];
299 [item setTitle: NSLocalizedStringFromTableInBundle(@"Unbold", nil, [NSBundle bundleForClass: [NSFontManager class]], @"Remove the bold font trait")];
302 [item setTag:NSBoldFontMask];
303 [item setTitle: NSLocalizedStringFromTableInBundle(@"Bold", nil, [NSBundle bundleForClass: [NSFontManager class]], @"Add the bold font trait")];
310 -(void)setSelectedFont:(NSFont *)font isMultiple:(BOOL)flag {
311 [_selectedFont autorelease];
312 _selectedFont=[font retain];
315 [[self fontPanel:NO] setPanelFont:font isMultiple:flag];
316 [self _configureMenu:[NSApp mainMenu] forFont:font];
319 - (void)_udpdateSelectedFont
322 NSFont *font = [self convertFont:_selectedFont];
323 if (font && font != _selectedFont) {
324 [self setSelectedFont:font isMultiple:_isMultiple];
329 -(NSFont *)convertFont:(NSFont *)font {
334 switch(_currentFontAction){
336 case NSNoFontChangeAction:
339 case NSViaPanelFontAction:
340 font=[_panel panelConvertFont:font];
343 case NSAddTraitFontAction:
344 font=[self convertFont:font toHaveTrait:_currentTrait];
347 case NSSizeUpFontAction:
348 font=[self convertFont:font toSize:[font pointSize]+1];
351 case NSSizeDownFontAction:{
352 float ps=[font pointSize];
356 font=[self convertFont:font toSize:ps];
360 case NSHeavierFontAction:
361 font=[self convertWeight:YES ofFont:font];
364 case NSLighterFontAction:
365 font=[self convertWeight:NO ofFont:font];
368 case NSRemoveTraitFontAction:
369 font=[self convertFont:font toNotHaveTrait:_currentTrait];
377 -(NSFont *)convertFont:(NSFont *)font toSize:(float)size {
378 if(size==[font pointSize])
381 return [NSFont fontWithName:[font fontName] size:size];
384 - (BOOL)_canConvertFont:(NSFont*)font toHaveTrait: (NSFontTraitMask)addTraits
386 NSFontFamily *family = [NSFontFamily fontFamilyWithTypefaceName: [font fontName]];
387 NSFontTypeface *typeface = [family typefaceWithName: [font fontName]];
388 NSFontTraitMask traits = [typeface traits];
390 if(addTraits & NSItalicFontMask) {
391 traits |= NSItalicFontMask;
394 if(addTraits & NSBoldFontMask) {
395 traits |= NSBoldFontMask;
398 if(addTraits & NSUnboldFontMask) {
399 traits &= ~NSBoldFontMask;
402 if(addTraits & NSUnitalicFontMask) {
403 traits &= ~NSItalicFontMask;
406 NSFontTypeface* newface = [family typefaceWithTraits:traits];
407 return newface != nil;
410 -(NSFont *)convertFont:(NSFont *)font toHaveTrait:(NSFontTraitMask)addTraits {
415 NSFontFamily *family=[NSFontFamily fontFamilyWithTypefaceName:[font fontName]];
416 NSFontTypeface *typeface=[family typefaceWithName:[font fontName]];
417 NSFontTraitMask traits=[typeface traits];
418 NSFontTypeface *newface;
420 if(addTraits&NSItalicFontMask)
421 traits|=NSItalicFontMask;
422 if(addTraits&NSBoldFontMask)
423 traits|=NSBoldFontMask;
424 if(addTraits&NSUnboldFontMask)
425 traits&=~NSBoldFontMask;
426 if(addTraits&NSUnitalicFontMask)
427 traits&=~NSItalicFontMask;
429 newface=[family typefaceWithTraits:traits];
432 return [NSFont fontWithName:[newface name] size:[font pointSize]];
434 NSLog(@"%s failed, %@ %d",sel_getName(_cmd),[font fontName],addTraits);
438 -(NSFont *)convertFont:(NSFont *)font toNotHaveTrait:(NSFontTraitMask)trait {
443 NSFontFamily *family=[NSFontFamily fontFamilyWithName: [font familyName]];
444 NSFontTypeface *typeface=[family typefaceWithName:[font fontName]];
445 NSFontTraitMask traits=[typeface traits];
446 traits &= ~trait; // remove the traits
447 NSFontTypeface *newface;
449 newface=[family typefaceWithTraits:traits];
452 return [NSFont fontWithName:[newface name] size:[font pointSize]];
454 NSLog(@"%s failed, %@ %d",sel_getName(_cmd),[font fontName],trait);
458 -(NSFont *)convertFont:(NSFont *)font toFace:(NSString *)typeface {
463 NSFont *convertedFont = [NSFont fontWithName: typeface size: [font pointSize]];
465 return convertedFont;
468 // Return the original font if the conversion fails - same as Apple
472 -(NSFont *)convertFont:(NSFont *)font toFamily:(NSString *)family {
477 // Get the current traits so we try and match them...
478 NSFontFamily *fontFamily=[NSFontFamily fontFamilyWithName: [font familyName]];
479 NSFontTypeface *typeface=[fontFamily typefaceWithName:[font fontName]];
480 NSFontTraitMask traits=[typeface traits];
481 return [self fontWithFamily: family traits: traits weight: 5 size: [font pointSize]];
484 -(NSFont *)convertWeight:(BOOL)heavierNotLighter ofFont:(NSFont *)font {
489 NSLog(@"convertWeight: %d ofFont: %@ ignored", heavierNotLighter, font);
493 -(NSDictionary *)convertAttributes:(NSDictionary *)attributes {
494 NSUnimplementedMethod();
498 -(void)addFontTrait:sender {
499 _currentTrait = [sender tag];
500 _currentFontAction = NSAddTraitFontAction;
504 [self _udpdateSelectedFont];
507 -(void)modifyFont:sender {
508 _currentFontAction=[sender tag];
512 [self _udpdateSelectedFont];
515 -(void)modifyFontViaPanel:sender {
516 _currentFontAction = NSViaPanelFontAction;
520 [self _udpdateSelectedFont];
523 -(void)removeFontTrait:sender {
524 _currentTrait = [sender tag];
525 _currentFontAction = NSRemoveTraitFontAction;
529 [self _udpdateSelectedFont];
532 -(void)orderFrontFontPanel:sender {
533 [[NSFontPanel sharedFontPanel] orderFront:sender];
536 -(void)orderFrontStylesPanel:sender {
537 NSUnimplementedMethod();
541 #pragma mark Font Menu Support
543 - (BOOL)validateMenuItem:(NSMenuItem*)item
546 SEL action = [item action];
547 if (action == @selector(addFontTrait:)) {
548 NSInteger tag = [item tag];
549 valid = [self _canConvertFont: [self selectedFont] toHaveTrait: tag];