diff --git a/AppKit/CPFont.j b/AppKit/CPFont.j index 16b34d42c..329a12111 100644 --- a/AppKit/CPFont.j +++ b/AppKit/CPFont.j @@ -251,6 +251,14 @@ following: return _CPUserFont(aName, aSize <= 0 ? _CPFontSystemFontSize : aSize, YES, italic); } +/*! + Internal font getter like fontWithName:size:italic: with a bold selector. +*/ ++ (CPFont)_fontWithName:(CPString)aName size:(float)aSize bold:(BOOL)bold italic:(BOOL)italic +{ + return _CPUserFont(aName, aSize <= 0 ? _CPFontSystemFontSize : aSize, bold, italic); +} + /*! Returns the system font scaled to the specified size @param aSize the size of the font (in px). 0 creates a static font diff --git a/AppKit/CPFontManager.j b/AppKit/CPFontManager.j index ddd39fc19..a55839fd6 100644 --- a/AppKit/CPFontManager.j +++ b/AppKit/CPFontManager.j @@ -24,6 +24,19 @@ @import "CPFont.j" +CPItalicFontMask = 1 << 0; +CPBoldFontMask = 1 << 1; +CPUnboldFontMask = 1 << 2; +CPNonStandardCharacterSetFontMask = 1 << 3; +CPNarrowFontMask = 1 << 4; +CPExpandedFontMask = 1 << 5; +CPCondensedFontMask = 1 << 6; +CPSmallCapsFontMask = 1 << 7; +CPPosterFontMask = 1 << 8; +CPCompressedFontMask = 1 << 9; +CPFixedPitchFontMask = 1 << 10; +CPUnitalicFontMask = 1 << 24; + var CPSharedFontManager = nil, CPFontManagerFactory = Nil; @@ -33,15 +46,17 @@ var CPSharedFontManager = nil, */ @implementation CPFontManager : CPObject { - CPArray _availableFonts; + CPArray _availableFonts; - id _target @accessors(property=target); - SEL _action @accessors(property=action); + id _target @accessors(property=target); + SEL _action @accessors(property=action); - id _delegate @accessors(property=delegate); + id _delegate @accessors(property=delegate); - CPFont _selectedFont; - BOOL _multiple @accessors; + CPFont _selectedFont; + BOOL _multiple @accessors; + + CPDictionary _activeChange; } // Getting the Shared Font Manager @@ -133,6 +148,47 @@ var CPSharedFontManager = nil, return _isMultiple; } +- (CPFont)convertFont:(CPFont)aFont +{ + if (!_activeChange) + return aFont; + + var addTraits = [_activeChange valueForKey:@"addTraits"]; + + if (addTraits) + aFont = [self convertFont:aFont toHaveTrait:addTraits]; + + return aFont; +} + +- (CPFont)convertFont:(CPFont)aFont toHaveTrait:(CPFontTraitMask)addTraits +{ + if (!aFont) + return nil; + + var shouldBeBold = ([aFont isBold] || (addTraits & CPBoldFontMask)) && !(addTraits & CPUnboldFontMask), + shouldBeItalic = ([aFont isItalic] || (addTraits & CPItalicFontMask)) && !(addTraits & CPUnitalicFontMask), + shouldBeSize = [aFont size]; + + // XXX On the current platform there will always be a bold/italic version of each font, but still leave + // || aFont in here for future platforms. + aFont = [CPFont _fontWithName:[aFont familyName] size:shouldBeSize bold:shouldBeBold italic:shouldBeItalic] || aFont; + + return aFont; +} + +- (@action)addFontTrait:(id)sender +{ + _activeChange = [CPDictionary dictionaryWithObject:[sender tag] forKey:@"addTraits"]; + + [self sendAction]; +} + +- (BOOL)sendAction +{ + return [CPApp sendAction:_action to:_target from:self]; +} + @end var _CPFontDetectSpan, diff --git a/Tests/AppKit/CPFontManagerTest.j b/Tests/AppKit/CPFontManagerTest.j index 4c1ebac26..795789912 100644 --- a/Tests/AppKit/CPFontManagerTest.j +++ b/Tests/AppKit/CPFontManagerTest.j @@ -1,7 +1,20 @@ @import +[CPApplication sharedApplication]; + @implementation CPFontManagerTest : OJTestCase { + CPFont fontA; + CPFont fontB; + CPFont convertedFontA; + CPFont convertedFontB; + + int tag @accessors; +} + +- (void)setUp +{ + fontA = [CPFont systemFontOfSize:8.0]; } - (void)testAvailableFonts @@ -13,8 +26,7 @@ - (void)testSetSelectedFont_isMultiple_ { - var fontManager = [CPFontManager sharedFontManager], - fontA = [CPFont systemFontOfSize:5.0]; + var fontManager = [CPFontManager sharedFontManager]; [fontManager setSelectedFont:fontA isMultiple:NO]; [self assert:[fontManager selectedFont] equals:fontA]; @@ -25,4 +37,61 @@ [self assertTrue:[fontManager isMultiple]]; } +- (void)testAddFontTrait_ +{ + var fontManager = [CPFontManager sharedFontManager]; + + [fontManager setSelectedFont:fontA isMultiple:NO]; + [fontManager setTarget:self]; + + fontB = [CPFont boldFontWithName:@"Helvetica" size:12.0 italic:YES]; + // Do nothing conversion. + [fontManager addFontTrait:self]; + + [self assert:fontA equals:convertedFontA message:@"fontA changed"]; + [self assert:fontB equals:convertedFontB message:@"fontB changed"]; + + // Add bold + tag = CPBoldFontMask; + [fontManager addFontTrait:self]; + + [self assertTrue:[convertedFontA isBold] message:@"add bold to fontA"]; + [self assertFalse:[convertedFontA isItalic] message:@"maintain no italics fontA"]; + [self assert:8.0 equals:[convertedFontA size]]; + + [self assertTrue:[convertedFontB isBold]]; + [self assertTrue:[convertedFontB isItalic]]; + [self assert:12.0 equals:[convertedFontB size]]; + + // Remove bold, add italic + tag = CPUnboldFontMask || CPItalicFontMask; + [fontManager addFontTrait:self]; + + [self assertFalse:[convertedFontA isBold] message:@"maintain no bold fontA with CPUnboldFontMask || CPItalicFontMask"]; + [self assertFalse:[convertedFontA isItalic] message:@"add italics fontA with CPUnboldFontMask || CPItalicFontMask"]; + [self assert:8.0 equals:[convertedFontA size] message:@"maintain size fontA with CPUnboldFontMask || CPItalicFontMask"]; + + [self assertFalse:[convertedFontB isBold] message:@"remove bold fontB with CPUnboldFontMask || CPItalicFontMask"]; + [self assertTrue:[convertedFontB isItalic] message:@"maintain italics fontB with CPUnboldFontMask || CPItalicFontMask"]; + [self assert:12.0 equals:[convertedFontB size] message:@"maintain size fontB with CPUnboldFontMask || CPItalicFontMask"]; + + // Remove italic + tag = CPUnitalicFontMask; + [fontManager addFontTrait:self]; + + [self assertFalse:[convertedFontA isBold] message:@"maintain no bold fontA with CPUnitalicFontMask"]; + [self assertFalse:[convertedFontA isItalic] message:@"maintain no italics fontA with CPUnitalicFontMask"]; + [self assert:8.0 equals:[convertedFontA size] message:@"maintain size fontA with CPUnitalicFontMask"]; + + [self assertTrue:[convertedFontB isBold] message:@"maintain bold fontB with CPUnitalicFontMask"]; + [self assertFalse:[convertedFontB isItalic] message:@"remove italics from fontB with CPUnitalicFontMask"]; + [self assert:12.0 equals:[convertedFontB size] message:@"maintain size fontB with CPUnitalicFontMask"]; +} + +- (@action)changeFont:(id)sender +{ + convertedFontA = [sender convertFont:fontA]; + convertedFontB = [sender convertFont:fontB]; +} + @end