diff --git a/FontReplacer Demo.xcodeproj/project.pbxproj b/FontReplacer Demo.xcodeproj/project.pbxproj index a8395d7..f69b126 100644 --- a/FontReplacer Demo.xcodeproj/project.pbxproj +++ b/FontReplacer Demo.xcodeproj/project.pbxproj @@ -7,9 +7,11 @@ objects = { /* Begin PBXBuildFile section */ + 6FB0365D14BFFEC900626500 /* AdjustmentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FB0365C14BFFEC900626500 /* AdjustmentViewController.m */; }; + 6FB0366014BFFEF500626500 /* AdjustmentViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6FB0365F14BFFEF500626500 /* AdjustmentViewController.xib */; }; + 6FB0366414C0030200626500 /* OBSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FB0366314C0030200626500 /* OBSlider.m */; }; DA336B6B13F01F5D00A60EA6 /* DemoViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA336B6A13F01F5D00A60EA6 /* DemoViewController.xib */; }; DA4C182113F446120015A600 /* FontsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4C181F13F446110015A600 /* FontsViewController.m */; }; - DA4C182813F4506A0015A600 /* ComparatorViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4C182613F450680015A600 /* ComparatorViewController.m */; }; DA6C855713F02703007060AF /* CaviarDreams.ttf in Resources */ = {isa = PBXBuildFile; fileRef = DA6C855213F02703007060AF /* CaviarDreams.ttf */; }; DA6C855813F02703007060AF /* CaviarDreams_Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = DA6C855313F02703007060AF /* CaviarDreams_Bold.ttf */; }; DA6C855913F02703007060AF /* CaviarDreams_BoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = DA6C855413F02703007060AF /* CaviarDreams_BoldItalic.ttf */; }; @@ -20,15 +22,17 @@ DA98620913F01BCE006DEC9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DA98620813F01BCE006DEC9A /* main.m */; }; DA98620D13F01BCE006DEC9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DA98620C13F01BCE006DEC9A /* AppDelegate.m */; }; DA98621C13F01E63006DEC9A /* UIFont+Replacement.m in Sources */ = {isa = PBXBuildFile; fileRef = DA98621B13F01E63006DEC9A /* UIFont+Replacement.m */; }; - DADAB65A13F5DDB0000301E6 /* ComparisonResult.m in Sources */ = {isa = PBXBuildFile; fileRef = DADAB65913F5DDB0000301E6 /* ComparisonResult.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 6FB0365B14BFFEC900626500 /* AdjustmentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdjustmentViewController.h; sourceTree = ""; }; + 6FB0365C14BFFEC900626500 /* AdjustmentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AdjustmentViewController.m; sourceTree = ""; }; + 6FB0365F14BFFEF500626500 /* AdjustmentViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AdjustmentViewController.xib; sourceTree = ""; }; + 6FB0366214C0030200626500 /* OBSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OBSlider.h; sourceTree = ""; }; + 6FB0366314C0030200626500 /* OBSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OBSlider.m; sourceTree = ""; }; DA336B6A13F01F5D00A60EA6 /* DemoViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DemoViewController.xib; sourceTree = ""; }; DA4C181E13F446110015A600 /* FontsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FontsViewController.h; sourceTree = ""; }; DA4C181F13F446110015A600 /* FontsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FontsViewController.m; sourceTree = ""; }; - DA4C182513F450680015A600 /* ComparatorViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ComparatorViewController.h; sourceTree = ""; }; - DA4C182613F450680015A600 /* ComparatorViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ComparatorViewController.m; sourceTree = ""; }; DA6C855213F02703007060AF /* CaviarDreams.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = CaviarDreams.ttf; sourceTree = ""; }; DA6C855313F02703007060AF /* CaviarDreams_Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = CaviarDreams_Bold.ttf; sourceTree = ""; }; DA6C855413F02703007060AF /* CaviarDreams_BoldItalic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = CaviarDreams_BoldItalic.ttf; sourceTree = ""; }; @@ -44,8 +48,6 @@ DA98620C13F01BCE006DEC9A /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; DA98621A13F01E63006DEC9A /* UIFont+Replacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIFont+Replacement.h"; sourceTree = ""; }; DA98621B13F01E63006DEC9A /* UIFont+Replacement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIFont+Replacement.m"; sourceTree = ""; }; - DADAB65813F5DDAF000301E6 /* ComparisonResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ComparisonResult.h; sourceTree = ""; }; - DADAB65913F5DDB0000301E6 /* ComparisonResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ComparisonResult.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -61,6 +63,16 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 6FB0366114C0030200626500 /* OBSlider */ = { + isa = PBXGroup; + children = ( + 6FB0366214C0030200626500 /* OBSlider.h */, + 6FB0366314C0030200626500 /* OBSlider.m */, + ); + name = OBSlider; + path = "FontReplacer Demo/OBSlider"; + sourceTree = ""; + }; DA6C855113F02703007060AF /* CaviarDreams */ = { isa = PBXGroup; children = ( @@ -75,12 +87,14 @@ DA9861EF13F01BCD006DEC9A = { isa = PBXGroup; children = ( + 6FB0366114C0030200626500 /* OBSlider */, DA98621913F01E55006DEC9A /* UIFont+Replacement */, DA98620213F01BCE006DEC9A /* FontReplacer Demo */, DA9861FD13F01BCE006DEC9A /* Frameworks */, DA9861FB13F01BCE006DEC9A /* Products */, ); sourceTree = ""; + usesTabs = 1; }; DA9861FB13F01BCE006DEC9A /* Products */ = { isa = PBXGroup; @@ -102,15 +116,14 @@ DA98620213F01BCE006DEC9A /* FontReplacer Demo */ = { isa = PBXGroup; children = ( + 6FB0365B14BFFEC900626500 /* AdjustmentViewController.h */, + 6FB0365C14BFFEC900626500 /* AdjustmentViewController.m */, + 6FB0365F14BFFEF500626500 /* AdjustmentViewController.xib */, DA98620B13F01BCE006DEC9A /* AppDelegate.h */, DA98620C13F01BCE006DEC9A /* AppDelegate.m */, DA336B6A13F01F5D00A60EA6 /* DemoViewController.xib */, DA4C181E13F446110015A600 /* FontsViewController.h */, DA4C181F13F446110015A600 /* FontsViewController.m */, - DA4C182513F450680015A600 /* ComparatorViewController.h */, - DA4C182613F450680015A600 /* ComparatorViewController.m */, - DADAB65813F5DDAF000301E6 /* ComparisonResult.h */, - DADAB65913F5DDB0000301E6 /* ComparisonResult.m */, DA6C855113F02703007060AF /* CaviarDreams */, DA98620313F01BCE006DEC9A /* Supporting Files */, ); @@ -194,6 +207,7 @@ DA6C855913F02703007060AF /* CaviarDreams_BoldItalic.ttf in Resources */, DA6C855A13F02703007060AF /* CaviarDreams_Italic.ttf in Resources */, DA6C856513F035EA007060AF /* Icon@2x.png in Resources */, + 6FB0366014BFFEF500626500 /* AdjustmentViewController.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -208,8 +222,8 @@ DA98620D13F01BCE006DEC9A /* AppDelegate.m in Sources */, DA98621C13F01E63006DEC9A /* UIFont+Replacement.m in Sources */, DA4C182113F446120015A600 /* FontsViewController.m in Sources */, - DA4C182813F4506A0015A600 /* ComparatorViewController.m in Sources */, - DADAB65A13F5DDB0000301E6 /* ComparisonResult.m in Sources */, + 6FB0365D14BFFEC900626500 /* AdjustmentViewController.m in Sources */, + 6FB0366414C0030200626500 /* OBSlider.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/FontReplacer Demo/AdjustmentViewController.h b/FontReplacer Demo/AdjustmentViewController.h new file mode 100644 index 0000000..a499f98 --- /dev/null +++ b/FontReplacer Demo/AdjustmentViewController.h @@ -0,0 +1,35 @@ +// +// AdjustmentViewController.h +// FontReplacer Demo +// +// Created by Samuel Défago on 13.01.12. +// Copyright (c) 2012 Cédric Lüthi. All rights reserved. +// + +#import + +#import "OBSlider.h" + +@interface AdjustmentViewController : UIViewController + +- (id) initWithReplacedFontName:(NSString *)replacedFontName replacementFontName:(NSString *)replacementFontName; + +@property (nonatomic, retain) IBOutlet UILabel *replacementFontFirstLabel; +@property (nonatomic, retain) IBOutlet UILabel *replacedFontFirstLabel; +@property (nonatomic, retain) IBOutlet UILabel *replacementFontSecondLabel; +@property (nonatomic, retain) IBOutlet UILabel *replacedFontSecondLabel; +@property (nonatomic, retain) IBOutlet UILabel *replacementFontThirdLabel; +@property (nonatomic, retain) IBOutlet UILabel *replacedFontThirdLabel; +@property (nonatomic, retain) IBOutlet UILabel *replacementFontFourthLabel; +@property (nonatomic, retain) IBOutlet UILabel *replacedFontFourthLabel; + +@property (nonatomic, retain) IBOutlet OBSlider *offsetSlider; +@property (nonatomic, retain) IBOutlet UILabel *offsetLabel; + +@property (nonatomic, retain) IBOutlet UISlider *pointSizeSlider; +@property (nonatomic, retain) IBOutlet UILabel *pointSizeLabel; + +- (IBAction) settingsChanged:(id)sender; +- (IBAction) save:(id)sender; + +@end diff --git a/FontReplacer Demo/AdjustmentViewController.m b/FontReplacer Demo/AdjustmentViewController.m new file mode 100644 index 0000000..6c63e96 --- /dev/null +++ b/FontReplacer Demo/AdjustmentViewController.m @@ -0,0 +1,257 @@ +// +// AdjustmentViewController.m +// FontReplacer Demo +// +// Created by Samuel Défago on 13.01.12. +// Copyright (c) 2012 Cédric Lüthi. All rights reserved. +// + +#import "AdjustmentViewController.h" + +#import "UIFont+Replacement.h" +#import + +@interface AdjustmentViewController () + +@property (nonatomic, retain) NSString *replacedFontName; +@property (nonatomic, retain) NSString *replacementFontName; + +- (void) releaseViews; + +- (void) reloadData; +- (void) reloadReplacedFontLabels; +- (void) reloadReplacementFontLabels; + +- (void) loadSettings; +- (void) saveSettings; + +- (NSString *) homeDirectory; +- (NSString *) settingsFilePath; + +@end + +@implementation AdjustmentViewController + +@synthesize replacedFontName = _replacedFontName; +@synthesize replacementFontName = _replacementFontName; + +@synthesize replacementFontFirstLabel = _font1FirstLabel; +@synthesize replacedFontFirstLabel = _font2FirstLabel; +@synthesize replacementFontSecondLabel = _font1SecondLabel; +@synthesize replacedFontSecondLabel = _font2SecondLabel; +@synthesize replacementFontThirdLabel = _font1ThirdLabel; +@synthesize replacedFontThirdLabel = _font2ThirdLabel; +@synthesize replacementFontFourthLabel = _font1FourthLabel; +@synthesize replacedFontFourthLabel = _font2FourthLabel; + +@synthesize offsetSlider = _factorSlider; +@synthesize offsetLabel = _offsetLabel; + +@synthesize pointSizeSlider = _pointSizeSlider; +@synthesize pointSizeLabel = _pointSizeLabel; + +// MARK: - Object creation and destruction + +- (id) initWithReplacedFontName:(NSString *)replacedFontName replacementFontName:(NSString *)replacementFontName +{ + if (!(self = [super initWithNibName:@"AdjustmentViewController" bundle:nil])) + return nil; + + self.replacedFontName = replacedFontName; + self.replacementFontName = replacementFontName; + self.title = @"Offset adjustment"; + return self; +} + +- (void) dealloc +{ + [self releaseViews]; + self.replacedFontName = nil; + self.replacementFontName = nil; + [super dealloc]; +} + +- (void) releaseViews +{ + self.replacementFontFirstLabel = nil; + self.replacedFontFirstLabel = nil; + self.replacementFontSecondLabel = nil; + self.replacedFontSecondLabel = nil; + self.replacementFontThirdLabel = nil; + self.replacedFontThirdLabel = nil; + self.replacementFontFourthLabel = nil; + self.replacedFontFourthLabel = nil; + self.offsetSlider = nil; + self.offsetLabel = nil; + self.pointSizeSlider = nil; + self.pointSizeLabel = nil; +} + +// MARK: - View lifecycle + +- (void) viewDidLoad +{ + [super viewDidLoad]; + + self.pointSizeSlider.value = self.replacementFontFirstLabel.font.pointSize; + self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave + target:self + action:@selector(save:)] autorelease]; + [self loadSettings]; +} + +- (void) viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + [self reloadData]; +} + +- (void) viewDidUnload +{ + [super viewDidUnload]; + [self releaseViews]; +} + +// MARK: - Reloading screen + +- (void) reloadData +{ + self.offsetLabel.text = [NSString stringWithFormat:@"%.3f", self.offsetSlider.value]; + self.pointSizeLabel.text = [NSString stringWithFormat:@"%d", (NSUInteger)self.pointSizeSlider.value]; + + // Reload the screen. This is made in two steps separated by a run loop. The reason for this trick (only needed + // for this special screen where we need both fonts to be displayed) is that drawing of the labels is made: + // - once without replacement dictionary (original replaced font) + // - once with replacement dictionary (replacement font) + // If we did all this within the same method (not separated by a run loop), drawing would not be correct since + // it doest not occur when we alter the font (it occurs when the display is refreshed afterwards). If both + // the following methods were called sequentially within the same run loop, the fonts would be correct but + // drawing would occur with the configuration of the last method which has been called (here with the dictionary + // installed). This would yield incorrect metrics for drawing the labels using the first font, leading to + // incorrect results (truncated labels in my tests) + [self reloadReplacedFontLabels]; + [self performSelector:@selector(reloadReplacementFontLabels) withObject:self afterDelay:0.]; +} + +- (void) reloadReplacedFontLabels +{ + [UIFont setReplacementDictionary:nil]; + + self.replacedFontFirstLabel.font = [UIFont fontWithName:self.replacedFontName size:floorf(self.pointSizeSlider.value)]; + self.replacedFontSecondLabel.font = [UIFont fontWithName:self.replacedFontName size:floorf(self.pointSizeSlider.value)]; + self.replacedFontThirdLabel.font = [UIFont fontWithName:self.replacedFontName size:floorf(self.pointSizeSlider.value)]; + self.replacedFontFourthLabel.font = [UIFont fontWithName:self.replacedFontName size:floorf(self.pointSizeSlider.value)]; +} + +- (void) reloadReplacementFontLabels +{ + NSMutableDictionary *replacementDictionary = [NSMutableDictionary dictionary]; + [replacementDictionary setObject:[NSDictionary dictionaryWithObjectsAndKeys:self.replacementFontName, @"Name", + [NSNumber numberWithFloat:self.offsetSlider.value], @"Offset", nil] + forKey:self.replacedFontName]; + [UIFont setReplacementDictionary:replacementDictionary]; + + self.replacementFontFirstLabel.font = [UIFont fontWithName:self.replacedFontName size:floorf(self.pointSizeSlider.value)]; + self.replacementFontSecondLabel.font = [UIFont fontWithName:self.replacedFontName size:floorf(self.pointSizeSlider.value)]; + self.replacementFontThirdLabel.font = [UIFont fontWithName:self.replacedFontName size:floorf(self.pointSizeSlider.value)]; + self.replacementFontFourthLabel.font = [UIFont fontWithName:self.replacedFontName size:floorf(self.pointSizeSlider.value)]; + + // Force a refresh + [self.replacementFontFirstLabel setNeedsDisplay]; + [self.replacementFontSecondLabel setNeedsDisplay]; + [self.replacementFontThirdLabel setNeedsDisplay]; + [self.replacementFontFourthLabel setNeedsDisplay]; +} + +// MARK: - Loading from and saving to a plist + +- (void) loadSettings +{ + NSString *settingsFilePath = [self settingsFilePath]; + NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:settingsFilePath]; + if (!settings) + { + self.offsetSlider.value = 0.f; + return; + } + + NSDictionary *replacementDictionary = [settings objectForKey:@"ReplacementFonts"]; + if (!replacementDictionary) + { + self.offsetSlider.value = 0.f; + return; + } + + NSDictionary *replacementInfoDictionary = [replacementDictionary objectForKey:self.replacedFontName]; + if (!replacementInfoDictionary) + { + self.offsetSlider.value = 0.f; + return; + } + + self.offsetSlider.value = [[replacementInfoDictionary objectForKey:@"Offset"] floatValue]; +} + +- (void) saveSettings +{ + NSString *settingsFilePath = [self settingsFilePath]; + NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithContentsOfFile:settingsFilePath] ?: [NSMutableDictionary dictionary]; + + // If the replacement font was already used, remove the existing entry + NSMutableDictionary *replacementDictionary = [NSMutableDictionary dictionaryWithDictionary:[settings objectForKey:@"ReplacementFonts"]]; + for (NSString *replacedFontName in [replacementDictionary allKeys]) + { + NSDictionary *replacementInfoDictionary = [replacementDictionary objectForKey:replacedFontName]; + if ([self.replacementFontName isEqualToString:[replacementInfoDictionary objectForKey:@"Name"]]) + { + [replacementDictionary removeObjectForKey:replacedFontName]; + } + } + + // Save settings + NSDictionary *replacementInfoDictionary = nil; + if (self.offsetSlider.value != 0) + { + replacementInfoDictionary = [NSDictionary dictionaryWithObjectsAndKeys:self.replacementFontName, @"Name", + [NSNumber numberWithFloat:self.offsetSlider.value], @"Offset", nil]; + } + else + { + replacementInfoDictionary = [NSDictionary dictionaryWithObjectsAndKeys:self.replacementFontName, @"Name", nil]; + } + [replacementDictionary setObject:replacementInfoDictionary forKey:self.replacedFontName]; + [settings setObject:replacementDictionary forKey:@"ReplacementFonts"]; + [settings writeToFile:settingsFilePath atomically:NO]; +} + +- (NSString *) homeDirectory +{ + NSString *logname = [NSString stringWithCString:getenv("LOGNAME") encoding:NSUTF8StringEncoding]; + struct passwd *pw = getpwnam([logname UTF8String]); + return pw ? [NSString stringWithCString:pw->pw_dir encoding:NSUTF8StringEncoding] : [@"/Users" stringByAppendingPathComponent:logname]; +} + +- (NSString *)settingsFilePath +{ +#if TARGET_IPHONE_SIMULATOR + NSString *saveDirectoryPath = [NSString stringWithFormat:@"%@/Desktop/", [self homeDirectory]]; +#else + NSString *saveDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; +#endif + return [saveDirectoryPath stringByAppendingPathComponent:@"FontReplacerSettings.plist"]; +} + +// MARK: - Event callbacks + +- (IBAction) settingsChanged:(id)sender +{ + [self reloadData]; +} + +- (IBAction) save:(id)sender +{ + [self saveSettings]; + [self.navigationController popToRootViewControllerAnimated:YES]; +} + +@end diff --git a/FontReplacer Demo/AdjustmentViewController.xib b/FontReplacer Demo/AdjustmentViewController.xib new file mode 100644 index 0000000..0b8ffba --- /dev/null +++ b/FontReplacer Demo/AdjustmentViewController.xib @@ -0,0 +1,773 @@ + + + + 1280 + 11C74 + 1938 + 1138.23 + 567.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 933 + + + IBUISlider + IBUIView + IBUILabel + IBProxyObject + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + + + + 292 + {{20, 2}, {280, 70}} + + + + NO + YES + 0.60000002384185791 + 7 + NO + IBCocoaTouchFramework + Sphinx + + 1 + MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA + + + 1 + 12 + 1 + + ArialMT + Arial + 0 + 18 + + + ArialMT + 18 + 16 + + + + + 292 + {{20, 2}, {280, 70}} + + + + NO + YES + 7 + NO + IBCocoaTouchFramework + Sphinx + + 1 + MCAwIDAAA + + + 1 + 12 + 1 + + + + + + 292 + {{20, 74}, {280, 70}} + + + + NO + YES + 0.60000002384185791 + 7 + NO + IBCocoaTouchFramework + befgix + + + 1 + 12 + 1 + + Arial-ItalicMT + Arial + 1 + 18 + + + Arial-ItalicMT + 18 + 16 + + + + + 292 + {{20, 74}, {280, 70}} + + + + NO + YES + 7 + NO + IBCocoaTouchFramework + befgix + + + 1 + 12 + 1 + + + + + + 292 + {{20, 146}, {280, 70}} + + + + NO + YES + 0.60000002384185791 + 7 + NO + IBCocoaTouchFramework + ACIQSW + + + 1 + 12 + 1 + + Arial-BoldMT + Arial + 2 + 18 + + + Arial-BoldMT + 18 + 16 + + + + + 292 + {{20, 146}, {280, 70}} + + + + NO + YES + 7 + NO + IBCocoaTouchFramework + ACIQSW + + + 1 + 12 + 1 + + + + + + 292 + {{20, 218}, {280, 70}} + + + + NO + YES + 0.60000002384185791 + 7 + NO + IBCocoaTouchFramework + 134580 + + + 1 + 12 + 1 + + Arial-BoldItalicMT + Arial + 3 + 18 + + + Arial-BoldItalicMT + 18 + 16 + + + + + 292 + {{20, 218}, {280, 70}} + + + + NO + YES + 7 + NO + IBCocoaTouchFramework + 134580 + + + 1 + 12 + 1 + + + + + + 292 + {{20, 291}, {52, 21}} + + + + _NS:328 + NO + YES + 7 + NO + IBCocoaTouchFramework + Offset + + + 1 + 10 + + 1 + 17 + + + Helvetica + 17 + 16 + + + + + 292 + {{78, 291}, {218, 23}} + + + + _NS:623 + NO + IBCocoaTouchFramework + 0 + 0 + -1 + + + + 292 + {{254, 307}, {40, 21}} + + + + _NS:328 + NO + YES + 7 + NO + IBCocoaTouchFramework + 9.999 + + + 1 + 10 + 2 + + 1 + 13 + + + Helvetica + 13 + 16 + + + + + 292 + {{20, 330}, {52, 21}} + + + + _NS:328 + NO + YES + 7 + NO + IBCocoaTouchFramework + Size + + + 1 + 10 + + + + + + 292 + {{78, 330}, {218, 23}} + + + + _NS:623 + NO + IBCocoaTouchFramework + 0 + 0 + 37 + 14 + 60 + + + + 292 + {{254, 346}, {40, 21}} + + + + _NS:328 + NO + YES + 7 + NO + IBCocoaTouchFramework + 99 + + + 1 + 10 + 2 + + + + + {{0, 64}, {320, 367}} + + + + + 3 + MC43NQA + + 2 + + + NO + + + NO + + + IBCocoaTouchFramework + + + + + + + view + + + + 16 + + + + pointSizeSlider + + + + 30 + + + + offsetSlider + + + + 41 + + + + offsetLabel + + + + 60 + + + + pointSizeLabel + + + + 61 + + + + replacedFontFirstLabel + + + + 70 + + + + replacementFontFirstLabel + + + + 71 + + + + replacedFontSecondLabel + + + + 72 + + + + replacementFontSecondLabel + + + + 73 + + + + replacedFontThirdLabel + + + + 74 + + + + replacementFontThirdLabel + + + + 75 + + + + replacedFontFourthLabel + + + + 76 + + + + replacementFontFourthLabel + + + + 77 + + + + settingsChanged: + + + 13 + + 42 + + + + settingsChanged: + + + 13 + + 43 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 4 + + + + + + + + + + + + + + + + + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + 14 + + + + + 15 + + + + + 54 + + + + + 55 + + + + + 56 + + + + + 57 + + + + + + + AdjustmentViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + OBSlider + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 77 + + + + + AdjustmentViewController + UIViewController + + id + id + + + + save: + id + + + settingsChanged: + id + + + + UILabel + OBSlider + UILabel + UISlider + UILabel + UILabel + UILabel + UILabel + UILabel + UILabel + UILabel + UILabel + + + + offsetLabel + UILabel + + + offsetSlider + OBSlider + + + pointSizeLabel + UILabel + + + pointSizeSlider + UISlider + + + replacedFontFirstLabel + UILabel + + + replacedFontFourthLabel + UILabel + + + replacedFontSecondLabel + UILabel + + + replacedFontThirdLabel + UILabel + + + replacementFontFirstLabel + UILabel + + + replacementFontFourthLabel + UILabel + + + replacementFontSecondLabel + UILabel + + + replacementFontThirdLabel + UILabel + + + + IBProjectSource + ./Classes/AdjustmentViewController.h + + + + OBSlider + UISlider + + IBProjectSource + ./Classes/OBSlider.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + 933 + + diff --git a/FontReplacer Demo/AppDelegate.h b/FontReplacer Demo/AppDelegate.h index 1b85cab..ac05cd4 100644 --- a/FontReplacer Demo/AppDelegate.h +++ b/FontReplacer Demo/AppDelegate.h @@ -6,8 +6,6 @@ // Copyright (c) 2011 Cédric Luthi. All rights reserved. // -@interface AppDelegate : UIResponder - -@property (nonatomic, retain) NSDictionary *originalReplacementDictionary; +@interface AppDelegate : UIResponder @end diff --git a/FontReplacer Demo/AppDelegate.m b/FontReplacer Demo/AppDelegate.m index a347c3e..60c622d 100644 --- a/FontReplacer Demo/AppDelegate.m +++ b/FontReplacer Demo/AppDelegate.m @@ -9,23 +9,18 @@ #import "AppDelegate.h" #import "FontsViewController.h" -#import "UIFont+Replacement.h" @implementation AppDelegate -@synthesize originalReplacementDictionary; - - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; UIViewController *demoViewController = [[UIViewController alloc] initWithNibName:@"DemoViewController" bundle:nil]; - UIViewController *fontsViewController = [[FontsViewController alloc] init]; + UIViewController *fontsViewController = [[[FontsViewController alloc] init] autorelease]; UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:fontsViewController]; UITabBarController *tabBarController = [[UITabBarController alloc] init]; - tabBarController.delegate = self; tabBarController.viewControllers = [NSArray arrayWithObjects:demoViewController, navigationController, nil]; demoViewController.title = @"Demo"; - fontsViewController.title = @"Fonts"; if ([window respondsToSelector:@selector(setRootViewController:)]) window.rootViewController = tabBarController; else @@ -34,18 +29,4 @@ - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions: return YES; } -- (BOOL) tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController -{ - if (tabBarController.selectedIndex == 0) - { - self.originalReplacementDictionary = [UIFont replacementDictionary]; - [UIFont setReplacementDictionary:nil]; - } - else - { - [UIFont setReplacementDictionary:self.originalReplacementDictionary]; - } - return YES; -} - @end diff --git a/FontReplacer Demo/ComparatorViewController.h b/FontReplacer Demo/ComparatorViewController.h deleted file mode 100644 index 599674d..0000000 --- a/FontReplacer Demo/ComparatorViewController.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// ComparatorViewController.h -// FontReplacer Demo -// -// Created by Cédric Luthi on 11.08.11. -// Copyright (c) 2011 Cédric Luthi. All rights reserved. -// - -@interface ComparatorViewController : UITableViewController -{ - NSMutableArray *results; -} - -- (id) initWithFontName:(NSString *)fontName; - -@end diff --git a/FontReplacer Demo/ComparatorViewController.m b/FontReplacer Demo/ComparatorViewController.m deleted file mode 100644 index f5ee345..0000000 --- a/FontReplacer Demo/ComparatorViewController.m +++ /dev/null @@ -1,86 +0,0 @@ -// -// ComparatorViewController.m -// FontReplacer Demo -// -// Created by Cédric Luthi on 11.08.11. -// Copyright (c) 2011 Cédric Luthi. All rights reserved. -// - -#import "ComparatorViewController.h" -#import "ComparisonResult.h" - -@implementation ComparatorViewController - -- (id) initWithFontName:(NSString *)fontName; -{ - if (!(self = [self initWithStyle:UITableViewStylePlain])) - return nil; - - self.title = fontName; - - const CGFloat fontSize = 12; - NSString *systemFamilyName = [UIFont systemFontOfSize:fontSize].familyName; - UIFont *font = [UIFont fontWithName:fontName size:fontSize]; - NSUInteger fontCount = [[UIFont fontNamesForFamilyName:font.familyName] count]; - results = [[NSMutableArray alloc] init]; - for (NSString *familyName in [[UIFont familyNames] sortedArrayUsingSelector:@selector(localizedCompare:)]) - { - NSArray *fontNames = [[UIFont fontNamesForFamilyName:familyName] sortedArrayUsingSelector:@selector(localizedCompare:)]; - if ([fontNames count] < fontCount || [familyName isEqualToString:font.familyName] || [familyName hasPrefix:systemFamilyName]) - continue; - - for (NSString *comparisonFontName in fontNames) - { - UIFont *comparisonFont = [UIFont fontWithName:comparisonFontName size:fontSize]; - // TODO: find the right formula - CGFloat score = fabsf(comparisonFont.ascender - font.ascender) + fabsf(comparisonFont.descender - font.descender) + fabsf(comparisonFont.capHeight - font.capHeight) - + fabsf(comparisonFont.xHeight - font.xHeight) + fabsf(comparisonFont.lineHeight - font.lineHeight); - ComparisonResult *result = [ComparisonResult resultWithFamilyName:familyName score:score]; - [results addObject:result]; - break; - } - } - [results sortUsingSelector:@selector(compare:)]; - - return self; -} - -- (void) dealloc -{ - [results release]; - [super dealloc]; -} - -// MARK: - Table View - -- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView -{ - return 1; -} - -- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section -{ - return [results count]; -} - -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - static NSString *CellIdentifier = @"Cell"; - - UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; - if (cell == nil) - cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease]; - - ComparisonResult *result = [results objectAtIndex:indexPath.row]; - cell.textLabel.text = result.familyName; - cell.detailTextLabel.text = [NSString stringWithFormat:@"%.2f", result.score]; - - return cell; -} - -- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath -{ - [self.navigationController popViewControllerAnimated:YES]; -} - -@end diff --git a/FontReplacer Demo/ComparisonResult.h b/FontReplacer Demo/ComparisonResult.h deleted file mode 100644 index a2e0f70..0000000 --- a/FontReplacer Demo/ComparisonResult.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// ComparisonResult.h -// FontReplacer Demo -// -// Created by Cédric Luthi on 13.08.11. -// Copyright (c) 2011 Cédric Luthi. All rights reserved. -// - -@interface ComparisonResult : NSObject - -+ (id) resultWithFamilyName:(NSString *)familyName score:(CGFloat)score; -- (id) initWithFamilyName:(NSString *)familyName score:(CGFloat)score; - -- (NSComparisonResult) compare:(ComparisonResult *)aResult; - -@property (nonatomic, retain) NSString *familyName; -@property (nonatomic, assign) CGFloat score; - -@end diff --git a/FontReplacer Demo/ComparisonResult.m b/FontReplacer Demo/ComparisonResult.m deleted file mode 100644 index 39e9e2f..0000000 --- a/FontReplacer Demo/ComparisonResult.m +++ /dev/null @@ -1,42 +0,0 @@ -// -// ComparisonResult.m -// FontReplacer Demo -// -// Created by Cédric Luthi on 13.08.11. -// Copyright (c) 2011 Cédric Luthi. All rights reserved. -// - -#import "ComparisonResult.h" - -@implementation ComparisonResult - -@synthesize familyName; -@synthesize score; - -+ (id) resultWithFamilyName:(NSString *)familyName score:(CGFloat)score -{ - return [[[self alloc] initWithFamilyName:familyName score:score] autorelease]; -} - -- (id) initWithFamilyName:(NSString *)aFamilyName score:(CGFloat)aScore -{ - if (!(self = [super init])) - return nil; - - self.familyName = aFamilyName; - self.score = aScore; - - return self; -} - -- (NSComparisonResult) compare:(ComparisonResult *)aResult -{ - if (aResult.score > self.score) - return NSOrderedAscending; - else if (aResult.score < self.score) - return NSOrderedDescending; - else - return NSOrderedSame; -} - -@end diff --git a/FontReplacer Demo/FontReplacer Demo-Info.plist b/FontReplacer Demo/FontReplacer Demo-Info.plist index 928160e..4f4116a 100644 --- a/FontReplacer Demo/FontReplacer Demo-Info.plist +++ b/FontReplacer Demo/FontReplacer Demo-Info.plist @@ -29,13 +29,27 @@ ReplacementFonts ArialMT - CaviarDreams + + Name + CaviarDreams + Arial-ItalicMT - CaviarDreams-Italic + + Name + CaviarDreams-Italic + Offset + 0.3 + Arial-BoldMT - CaviarDreams-Bold + + Name + CaviarDreams-Bold + Arial-BoldItalicMT - CaviarDreams-BoldItalic + + Name + CaviarDreams-BoldItalic + UIAppFonts diff --git a/FontReplacer Demo/FontsViewController.h b/FontReplacer Demo/FontsViewController.h index 97464a8..f42c652 100644 --- a/FontReplacer Demo/FontsViewController.h +++ b/FontReplacer Demo/FontsViewController.h @@ -13,4 +13,6 @@ NSArray *familyNames; } +@property (nonatomic, retain) NSString *replacementFontName; + @end diff --git a/FontReplacer Demo/FontsViewController.m b/FontReplacer Demo/FontsViewController.m index 635149d..8b9c2bb 100644 --- a/FontReplacer Demo/FontsViewController.m +++ b/FontReplacer Demo/FontsViewController.m @@ -7,16 +7,25 @@ // #import "FontsViewController.h" -#import "ComparatorViewController.h" + +#import "AdjustmentViewController.h" +#import "UIFont+Replacement.h" + +@interface FontsViewController () + +- (void) reloadData; + +@end @implementation FontsViewController - (id) init { - if (!(self = [self initWithStyle:UITableViewStylePlain])) + if (!(self = [super initWithStyle:UITableViewStylePlain])) return nil; familyNames = [[[UIFont familyNames] sortedArrayUsingSelector:@selector(localizedCompare:)] retain]; + self.title = @"Replacement font"; return self; } @@ -27,6 +36,48 @@ - (void) dealloc [super dealloc]; } +// MARK: - Accessors and mutators + +@synthesize replacementFontName = _replacementFontName; + +- (void) setReplacementFontName:(NSString *)replacementFontName +{ + if (_replacementFontName == replacementFontName) + return; + + [_replacementFontName release]; + _replacementFontName = [replacementFontName retain]; + + [self reloadData]; +} + +// MARK: - View lifecycle + +- (void) viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + [UIFont setReplacementDictionary:nil]; + + // Fixes a strange issue: If the table view is reloaded directly, fonts are not updated correctly. Doing it + // in the next run loop iteration fixes this issue + [self performSelector:@selector(reloadData) withObject:nil afterDelay:0.]; +} + +- (void) viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + NSDictionary *plistDictionary = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"ReplacementFonts"]; + [UIFont setReplacementDictionary:plistDictionary]; +} + +// MARK: - Reloading the screen + +- (void) reloadData +{ + self.title = self.replacementFontName ? @"Replaced font" : @"Replacement font"; + [self.tableView reloadData]; +} + // MARK: - Table View - (NSArray *) fontNamesForSection:(NSInteger)section @@ -88,8 +139,18 @@ - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath { NSString *fontName = [self fontNameAtIndexPath:indexPath]; - ComparatorViewController *comparatorViewController = [[ComparatorViewController alloc] initWithFontName:fontName]; - [self.navigationController pushViewController:comparatorViewController animated:YES]; + if (self.replacementFontName) + { + AdjustmentViewController *adjustmentViewController = [[[AdjustmentViewController alloc] initWithReplacedFontName:fontName + replacementFontName:self.replacementFontName] autorelease]; + [self.navigationController pushViewController:adjustmentViewController animated:YES]; + } + else + { + FontsViewController *fontsViewController = [[[FontsViewController alloc] init] autorelease]; + fontsViewController.replacementFontName = fontName; + [self.navigationController pushViewController:fontsViewController animated:YES]; + } } @end diff --git a/FontReplacer Demo/OBSlider/OBSlider.h b/FontReplacer Demo/OBSlider/OBSlider.h new file mode 100644 index 0000000..619836d --- /dev/null +++ b/FontReplacer Demo/OBSlider/OBSlider.h @@ -0,0 +1,26 @@ +// +// OBSlider.h +// +// Created by Ole Begemann on 02.01.11. +// Copyright 2011 Ole Begemann. All rights reserved. +// + +#import + + +@interface OBSlider : UISlider +{ + float scrubbingSpeed; + NSArray *scrubbingSpeeds; + NSArray *scrubbingSpeedChangePositions; + + CGPoint beganTrackingLocation; + + float realPositionValue; +} + +@property (assign, readonly) float scrubbingSpeed; +@property (retain) NSArray *scrubbingSpeeds; +@property (retain) NSArray *scrubbingSpeedChangePositions; + +@end diff --git a/FontReplacer Demo/OBSlider/OBSlider.m b/FontReplacer Demo/OBSlider/OBSlider.m new file mode 100644 index 0000000..90d7a57 --- /dev/null +++ b/FontReplacer Demo/OBSlider/OBSlider.m @@ -0,0 +1,196 @@ +// +// OBSlider.m +// +// Created by Ole Begemann on 02.01.11. +// Copyright 2011 Ole Begemann. All rights reserved. +// + +#import "OBSlider.h" + + +@interface OBSlider () + +@property (assign, readwrite) float scrubbingSpeed; +@property (assign) CGPoint beganTrackingLocation; + +- (NSUInteger) indexOfLowerScrubbingSpeed:(NSArray*)scrubbingSpeedPositions forOffset:(CGFloat)verticalOffset; +- (NSArray *) defaultScrubbingSpeeds; +- (NSArray *) defaultScrubbingSpeedChangePositions; + +@end + + + +@implementation OBSlider + +@synthesize scrubbingSpeed; +@synthesize scrubbingSpeeds; +@synthesize scrubbingSpeedChangePositions; +@synthesize beganTrackingLocation; + + +- (void) dealloc +{ + self.scrubbingSpeeds = nil; + self.scrubbingSpeedChangePositions = nil; + [super dealloc]; +} + + +- (id) initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self != nil) + { + self.scrubbingSpeeds = [self defaultScrubbingSpeeds]; + self.scrubbingSpeedChangePositions = [self defaultScrubbingSpeedChangePositions]; + self.scrubbingSpeed = [[self.scrubbingSpeeds objectAtIndex:0] floatValue]; + } + return self; +} + + + +#pragma mark - +#pragma mark NSCoding + +- (id) initWithCoder:(NSCoder *)decoder +{ + self = [super initWithCoder:decoder]; + if (self != nil) + { + if ([decoder containsValueForKey:@"scrubbingSpeeds"]) { + self.scrubbingSpeeds = [decoder decodeObjectForKey:@"scrubbingSpeeds"]; + } else { + self.scrubbingSpeeds = [self defaultScrubbingSpeeds]; + } + + if ([decoder containsValueForKey:@"scrubbingSpeedChangePositions"]) { + self.scrubbingSpeedChangePositions = [decoder decodeObjectForKey:@"scrubbingSpeedChangePositions"]; + } else { + self.scrubbingSpeedChangePositions = [self defaultScrubbingSpeedChangePositions]; + } + + self.scrubbingSpeed = [[self.scrubbingSpeeds objectAtIndex:0] floatValue]; + } + return self; +} + + +- (void) encodeWithCoder:(NSCoder *)coder +{ + [super encodeWithCoder:coder]; + + [coder encodeObject:self.scrubbingSpeeds forKey:@"scrubbingSpeeds"]; + [coder encodeObject:self.scrubbingSpeedChangePositions forKey:@"scrubbingSpeedChangePositions"]; + + // No need to archive self.scrubbingSpeed as it is calculated from the arrays on init +} + + + +#pragma mark - +#pragma mark Touch tracking + +- (BOOL) beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event +{ + BOOL beginTracking = [super beginTrackingWithTouch:touch withEvent:event]; + if (beginTracking) + { + self.beganTrackingLocation = [touch locationInView:self]; + realPositionValue = self.value; + } + return beginTracking; +} + + +- (BOOL) continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event +{ + if (self.tracking) + { + CGPoint previousLocation = [touch previousLocationInView:self]; + CGPoint currentLocation = [touch locationInView:self]; + CGFloat trackingOffset = currentLocation.x - previousLocation.x; + + // Find the scrubbing speed that curresponds to the touch's vertical offset + CGFloat verticalOffset = fabsf(currentLocation.y - self.beganTrackingLocation.y); + NSUInteger scrubbingSpeedChangePosIndex = [self indexOfLowerScrubbingSpeed:self.scrubbingSpeedChangePositions forOffset:verticalOffset]; + if (scrubbingSpeedChangePosIndex == NSNotFound) { + scrubbingSpeedChangePosIndex = [self.scrubbingSpeeds count]; + } + self.scrubbingSpeed = [[self.scrubbingSpeeds objectAtIndex:scrubbingSpeedChangePosIndex - 1] floatValue]; + + CGRect trackRect = [self trackRectForBounds:self.bounds]; + realPositionValue = realPositionValue + (self.maximumValue - self.minimumValue) * (trackingOffset / trackRect.size.width); + if ( ((self.beganTrackingLocation.y < currentLocation.y) && (currentLocation.y < previousLocation.y)) || + ((self.beganTrackingLocation.y > currentLocation.y) && (currentLocation.y > previousLocation.y)) ) + { + // We are getting closer to the slider, go closer to the real location + self.value = self.value + self.scrubbingSpeed * (self.maximumValue - self.minimumValue) * (trackingOffset / trackRect.size.width) + (realPositionValue - self.value) / ( 1 + fabsf(currentLocation.y - self.beganTrackingLocation.y)); + } else { + self.value = self.value + self.scrubbingSpeed * (self.maximumValue - self.minimumValue) * (trackingOffset / trackRect.size.width); + } + + if (self.continuous) { + [self sendActionsForControlEvents:UIControlEventValueChanged]; + } + } + return self.tracking; +} + + +- (void) endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event +{ + if (self.tracking) + { + self.scrubbingSpeed = [[self.scrubbingSpeeds objectAtIndex:0] floatValue]; + [self sendActionsForControlEvents:UIControlEventValueChanged]; + } +} + + + +#pragma mark - +#pragma mark Helper methods + +// Return the lowest index in the array of numbers passed in scrubbingSpeedPositions +// whose value is smaller than verticalOffset. +- (NSUInteger) indexOfLowerScrubbingSpeed:(NSArray*)scrubbingSpeedPositions forOffset:(CGFloat)verticalOffset +{ + for (NSUInteger i = 0; i < [scrubbingSpeedPositions count]; i++) { + NSNumber *scrubbingSpeedOffset = [scrubbingSpeedPositions objectAtIndex:i]; + if (verticalOffset < [scrubbingSpeedOffset floatValue]) { + return i; + } + } + return NSNotFound; +} + + + +#pragma mark - +#pragma mark Default values + +// Used in -initWithFrame: and -initWithCoder: +- (NSArray *) defaultScrubbingSpeeds +{ + return [NSArray arrayWithObjects: + [NSNumber numberWithFloat:1.0f], + [NSNumber numberWithFloat:0.5f], + [NSNumber numberWithFloat:0.25f], + [NSNumber numberWithFloat:0.1f], + nil]; +} + + +- (NSArray *) defaultScrubbingSpeedChangePositions +{ + return [NSArray arrayWithObjects: + [NSNumber numberWithFloat:0.0f], + [NSNumber numberWithFloat:50.0f], + [NSNumber numberWithFloat:100.0f], + [NSNumber numberWithFloat:150.0f], + nil]; +} + +@end diff --git a/UIFont+Replacement/UIFont+Replacement.m b/UIFont+Replacement/UIFont+Replacement.m index 47ca968..df96dd4 100644 --- a/UIFont+Replacement/UIFont+Replacement.m +++ b/UIFont+Replacement/UIFont+Replacement.m @@ -12,6 +12,7 @@ @implementation UIFont (Replacement) static NSDictionary *replacementDictionary = nil; +static NSDictionary *inverseReplacementDictionary = nil; static void initializeReplacementFonts() { @@ -30,25 +31,69 @@ + (void) load Method fontWithName_size_traits_ = class_getClassMethod([UIFont class], @selector(fontWithName:size:traits:)); Method replacementFontWithName_size_ = class_getClassMethod([UIFont class], @selector(replacement_fontWithName:size:)); Method replacementFontWithName_size_traits_ = class_getClassMethod([UIFont class], @selector(replacement_fontWithName:size:traits:)); - + if (fontWithName_size_ && replacementFontWithName_size_ && strcmp(method_getTypeEncoding(fontWithName_size_), method_getTypeEncoding(replacementFontWithName_size_)) == 0) method_exchangeImplementations(fontWithName_size_, replacementFontWithName_size_); if (fontWithName_size_traits_ && replacementFontWithName_size_traits_ && strcmp(method_getTypeEncoding(fontWithName_size_traits_), method_getTypeEncoding(replacementFontWithName_size_traits_)) == 0) method_exchangeImplementations(fontWithName_size_traits_, replacementFontWithName_size_traits_); + + Method ascender_ = class_getInstanceMethod([UIFont class], @selector(ascender)); + Method replacementAscender_ = class_getInstanceMethod([UIFont class], @selector(replacement_ascender)); + if (ascender_ && replacementAscender_ && strcmp(method_getTypeEncoding(ascender_), method_getTypeEncoding(replacementAscender_)) == 0) + method_exchangeImplementations(ascender_, replacementAscender_); +} + ++ (NSDictionary *) replacementInfoForFontWithName:(NSString *)fontName +{ + if (!replacementDictionary) + return nil; + + return [replacementDictionary objectForKey:fontName]; +} + ++ (NSString *) replacementFontNameForFontWithName:(NSString *)fontName +{ + return [[self replacementInfoForFontWithName:fontName] objectForKey:@"Name"] ?: fontName; +} + ++ (CGFloat) offsetForFontWithName:(NSString *)fontName +{ + return [[[self replacementInfoForFontWithName:fontName] objectForKey:@"Offset"] floatValue]; } + (UIFont *) replacement_fontWithName:(NSString *)fontName size:(CGFloat)fontSize { initializeReplacementFonts(); - NSString *replacementFontName = [replacementDictionary objectForKey:fontName]; - return [self replacement_fontWithName:replacementFontName ?: fontName size:fontSize]; + return [self replacement_fontWithName:[self replacementFontNameForFontWithName:fontName] size:fontSize]; } + (UIFont *) replacement_fontWithName:(NSString *)fontName size:(CGFloat)fontSize traits:(int)traits { initializeReplacementFonts(); - NSString *replacementFontName = [replacementDictionary objectForKey:fontName]; - return [self replacement_fontWithName:replacementFontName ?: fontName size:fontSize traits:traits]; + return [self replacement_fontWithName:[self replacementFontNameForFontWithName:fontName] size:fontSize traits:traits]; +} + +- (CGFloat) replacement_ascender +{ + NSString *fontName = [self fontName]; + CGFloat ascender = [self replacement_ascender]; + + // The receiver is not replacing any font. Return the original ascender value + NSString *replacedFontName = [inverseReplacementDictionary objectForKey:fontName]; + if (!replacedFontName) + return ascender; + + // The receiver is replacing another font: To access the replaced UIFont object, we have to remove the replacement dictionary + // temporarily + NSDictionary *originalReplacementDictionary = [[[UIFont replacementDictionary] retain] autorelease]; + [UIFont setReplacementDictionary:nil]; + UIFont *replacedFont = [UIFont fontWithName:replacedFontName size:self.pointSize]; + [UIFont setReplacementDictionary:originalReplacementDictionary]; + + // Adjust the receiver ascender value. A good default behavior is to have the ascender value of the replacing + // font match the one of the replaced font. If this default behavior is not convincing enough, an offset + // can be optionally provided in the plist settings + return [replacedFont replacement_ascender] + self.pointSize * [UIFont offsetForFontWithName:replacedFontName]; } + (NSDictionary *) replacementDictionary @@ -61,6 +106,7 @@ + (void) setReplacementDictionary:(NSDictionary *)aReplacementDictionary if (aReplacementDictionary == replacementDictionary) return; + NSMutableDictionary *anInverseReplacementDictionary = [NSMutableDictionary dictionary]; for (id key in [aReplacementDictionary allKeys]) { if (![key isKindOfClass:[NSString class]]) @@ -69,24 +115,43 @@ + (void) setReplacementDictionary:(NSDictionary *)aReplacementDictionary return; } - id value = [aReplacementDictionary valueForKey:key]; - if (![value isKindOfClass:[NSString class]]) + NSString *fontName = (NSString *)key; + id value = [aReplacementDictionary valueForKey:fontName]; + if (![value isKindOfClass:[NSDictionary class]]) { - NSLog(@"ERROR: Replacement font value must be a string."); + NSLog(@"ERROR: Replacement font value must be a dictionary."); return; } + + NSDictionary *replacementInfo = (NSDictionary *)value; + NSString *replacementFontName = [replacementInfo objectForKey:@"Name"]; + if (!replacementFontName) + { + NSLog(@"ERROR: Missing replacement font name for font '%@'", fontName); + return; + } + + UIFont *font = [UIFont fontWithName:replacementFontName size:10.f]; + if (!font) + { + NSLog(@"ERROR: The replacement font '%@' is not available", replacementFontName); + return; + } + + if ([anInverseReplacementDictionary objectForKey:replacementFontName]) + { + NSLog(@"ERROR: A font can replace at most one other font. This is not the case for font '%@'", replacementFontName); + return; + } + + [anInverseReplacementDictionary setObject:fontName forKey:replacementFontName]; } [replacementDictionary release]; replacementDictionary = [aReplacementDictionary retain]; - for (id key in [replacementDictionary allKeys]) - { - NSString *fontName = [replacementDictionary objectForKey:key]; - UIFont *font = [UIFont fontWithName:fontName size:10]; - if (!font) - NSLog(@"WARNING: replacement font '%@' is not available.", fontName); - } + [inverseReplacementDictionary release]; + inverseReplacementDictionary = [anInverseReplacementDictionary retain]; } @end