// // MPParenthesisFunctionLayout.m // MathPad // // Created by Kim Wittenburg on 17.09.14. // Copyright (c) 2014 Kim Wittenburg. All rights reserved. // #import "MPParenthesisFunctionLayout.h" #import "MPParenthesisFunction.h" #define MPParenthesisFunctionOpeningParensOffset 2 #define MPParenthesisFunctionClosingParensOffset 0 @interface MPParenthesisFunctionLayout () - (NSBezierPath *)openingParens; - (NSBezierPath *)closingParens; - (NSBezierPath *)transformedOpeningParens; - (NSBezierPath *)transformedClosingParens; - (NSAffineTransform *)parenthesisTransform; @end @implementation MPParenthesisFunctionLayout - (MPParenthesisFunction *)parenthesisFunction { return (MPParenthesisFunction *)self.function; } - (NSBezierPath *)openingParens { NSBezierPath *parens = [self objectForPrivateCacheIndex:0 generator:^id{ CTLineRef line = [self createLineForString:@"("]; CFArrayRef glyphRuns = CTLineGetGlyphRuns(line); CFRetain(glyphRuns); CTRunRef glyphRun = CFArrayGetValueAtIndex(glyphRuns, 0); CFRetain(glyphRun); CGGlyph *glyphs = malloc(1 * sizeof(CGGlyph)); CTRunGetGlyphs(glyphRun, CFRangeMake(0, 1), glyphs); NSGlyph glyph = glyphs[0]; NSBezierPath *path = [[NSBezierPath alloc] init]; [path moveToPoint:NSZeroPoint]; [path appendBezierPathWithGlyph:glyph inFont:self.font]; CFRelease(line); CFRelease(glyphRuns); CFRelease(glyphRun); free(glyphs); return path; }]; return parens; } - (NSBezierPath *)closingParens { NSBezierPath *parens = [self objectForPrivateCacheIndex:1 generator:^id{ CTLineRef line = [self createLineForString:@")"]; CFArrayRef glyphRuns = CTLineGetGlyphRuns(line); CFRetain(glyphRuns); CTRunRef glyphRun = CFArrayGetValueAtIndex(glyphRuns, 0); CFRetain(glyphRun); CGGlyph *glyphs = malloc(1 * sizeof(CGGlyph)); CTRunGetGlyphs(glyphRun, CFRangeMake(0, 1), glyphs); NSGlyph glyph = glyphs[0]; NSBezierPath *path = [[NSBezierPath alloc] init]; [path moveToPoint:NSZeroPoint]; [path appendBezierPathWithGlyph:glyph inFont:self.font]; CFRelease(line); CFRelease(glyphRuns); CFRelease(glyphRun); free(glyphs); return path; }]; return parens; } - (NSBezierPath *)transformedOpeningParens { NSBezierPath *parens = self.openingParens.copy; [parens transformUsingAffineTransform:self.parenthesisTransform]; return parens; } - (NSBezierPath *)transformedClosingParens { NSBezierPath *parens = self.closingParens.copy; [parens transformUsingAffineTransform:self.parenthesisTransform]; return parens; } - (NSAffineTransform *)parenthesisTransform { NSAffineTransform *transform = [NSAffineTransform transform]; [transform scaleXBy:1 yBy:self.scaleFactor]; return transform; } - (CGFloat)scaleFactor { NSRect parensBounds = self.openingParens.bounds; NSRect expressionBounds = [self childLayoutAtIndex:0].bounds; CGFloat parensHeight = parensBounds.size.height; CGFloat expressionHeight = expressionBounds.size.height; if (expressionHeight <= parensHeight) { return 1.0; } return expressionHeight / parensHeight; } - (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index { return NSMakePoint(self.openingParens.bounds.size.width + MPParenthesisFunctionOpeningParensOffset, 0); } - (NSIndexPath *)indexPathForLocalMousePoint:(NSPoint)point { return [NSIndexPath indexPathWithIndex:0]; } - (NSIndexSet *)indexesOfRemainingChildren { return [NSIndexSet indexSetWithIndex:0]; } - (NSRect)generateBounds { NSRect openingParensBounds = self.transformedOpeningParens.bounds; NSRect closingParensBounds = self.transformedClosingParens.bounds; NSRect bounds = [self childLayoutAtIndex:0].bounds; if (openingParensBounds.size.height > bounds.size.height) { bounds.size.height = openingParensBounds.size.height; } if (closingParensBounds.size.height > bounds.size.height) { bounds.size.height = closingParensBounds.size.height; } bounds.size.width += MPParenthesisFunctionOpeningParensOffset; bounds.size.width += openingParensBounds.size.width; bounds.size.width += MPParenthesisFunctionClosingParensOffset; bounds.size.width += closingParensBounds.size.width; return bounds; } - (void)draw { NSBezierPath *openingParens = self.transformedOpeningParens; MPLayout *expressionLayout = [self childLayoutAtIndex:0]; NSBezierPath *closingParens = self.transformedClosingParens; CGFloat x = 0; CGFloat y = -openingParens.bounds.origin.y + expressionLayout.bounds.origin.y; NSAffineTransform *transform = [NSAffineTransform transform]; [transform translateXBy:0 yBy:y]; [openingParens transformUsingAffineTransform:transform]; [openingParens fill]; x += openingParens.bounds.size.width; x += MPParenthesisFunctionOpeningParensOffset; x += expressionLayout.bounds.size.width; x += MPParenthesisFunctionClosingParensOffset; [transform translateXBy:x yBy:0]; [closingParens transformUsingAffineTransform:transform]; [closingParens fill]; } @end