// // MPExpressionLayout.m // MathPad // // Created by Kim Wittenburg on 07.08.14. // Copyright (c) 2014 Kim Wittenburg. All rights reserved. // #import "MPExpressionLayout.h" #import "MPFunctionLayout.h" @interface MPExpressionLayout (MPPathGeneration) - (NSBezierPath *)bezierPathForChildAtIndex:(NSUInteger)index; - (NSBezierPath *)generateBezierPathForString:(NSString *)aString; @end @implementation MPExpressionLayout (MPPathGeneration) - (NSBezierPath *)bezierPathForChildAtIndex:(NSUInteger)index { id symbol = [self.expression elementAtIndex:index]; if ([symbol isString]) { return [self cachableObjectForIndex:index generator:^id{ return [self generateBezierPathForString:symbol]; }]; } else { MPLayout *layout = [self childLayoutAtIndex:index]; return layout.bezierPath; } } - (NSBezierPath *)generateBezierPathForString:(NSString *)aString { NSAttributedString *text = [[NSAttributedString alloc] initWithString:aString attributes:@{NSFontAttributeName: [NSFont fontWithName:@"Lucida Grande" size:18.0]}]; self.textStorage.attributedString = text; NSRange glyphRange = [self.layoutManager glyphRangeForTextContainer:self.textContainer]; NSGlyph glyphs[glyphRange.length+1]; NSUInteger actualGlyphCount = [self.layoutManager getGlyphs:glyphs range:glyphRange]; NSBezierPath *path = [NSBezierPath bezierPath]; [path moveToPoint:NSZeroPoint]; [path appendBezierPathWithGlyphs:glyphs count:actualGlyphCount inFont:[NSFont fontWithName:@"Lucida Grande" size:18.0]]; return path; } @end @implementation MPExpressionLayout # pragma mark Creation Methods - (instancetype)initRootLayoutWithExpressionStorage:(MPExpressionStorage *)expressionStorage { self = [super init]; if (self) { _expressionStorage = expressionStorage; } return self; } #pragma mark Properties @synthesize expressionStorage = _expressionStorage; - (MPExpressionStorage *)expressionStorage { if (_expressionStorage) { return _expressionStorage; } return self.parent.expressionStorage; } - (MPExpression *)expression { return [self.expressionStorage elementAtIndexPath:self.path]; } #pragma mark Cache Methods - (MPLayout *)childLayoutAtIndex:(NSUInteger)index { id cachedObject = [self cachableObjectForIndex:index generator:^id{ NSIndexPath *indexPath = [self.path indexPathByAddingIndex:index]; MPFunctionLayout *layout = [MPFunctionLayout functionLayoutForFunctionAtIndexPath:indexPath parent:self]; return layout; }]; if ([cachedObject isKindOfClass:[NSBezierPath class]]) { return nil; } return cachedObject; } - (NSSize)sizeForChildAtIndex:(NSUInteger)index { id symbol = [self.expression elementAtIndex:index]; if ([symbol isString]) { return [self bezierPathForChildAtIndex:index].bounds.size; } else { return [self childLayoutAtIndex:index].size; } } #pragma mark Drawing Methods - (NSBezierPath *)generateBezierPath { NSBezierPath *fullPath = [NSBezierPath bezierPath]; [fullPath moveToPoint:NSZeroPoint]; NSUInteger x = 0; for (NSInteger index = 0; index < self.expression.numberOfElements; ++index) { NSAffineTransform *transform = [NSAffineTransform transform]; // TODO: Translate by the right amount [transform translateXBy:x yBy:0]; NSBezierPath *path = [self bezierPathForChildAtIndex:index].copy; [path transformUsingAffineTransform:transform]; [fullPath appendBezierPath:path]; x += path.bounds.size.width; } return fullPath; } @end