// // MPParenthesisFunctionLayout.m // MathPad // // Created by Kim Wittenburg on 17.09.14. // Copyright (c) 2014 Kim Wittenburg. All rights reserved. // #import "MPParenthesisFunctionLayout.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 { NSRect parensBounds = self.openingParens.bounds; NSRect expressionBounds = [self childLayoutAtIndex:0].bounds; NSAffineTransform *transform = [NSAffineTransform transform]; if (expressionBounds.size.height >= parensBounds.size.height) { return transform; } CGFloat scaleFactor = expressionBounds.size.height / parensBounds.size.height; [transform scaleXBy:1 yBy:scaleFactor]; return transform; } - (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index { if (index == 0) { return NSMakePoint(self.openingParens.bounds.size.width + MPParenthesisFunctionOpeningParensOffset, 0); } return NSZeroPoint; } - (NSIndexPath *)indexPathForLocalMousePoint:(NSPoint)point { #warning Missing Implementation 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; } #warning Let the children be drawn automatically - (BOOL)drawsChildrenManually { return YES; } - (void)draw { NSBezierPath *openingParens = self.transformedOpeningParens; MPLayout *expressionLayout = [self childLayoutAtIndex:0]; NSBezierPath *closingParens = self.transformedClosingParens; CGFloat x = 0; [openingParens fill]; x += openingParens.bounds.size.width; x += MPParenthesisFunctionOpeningParensOffset; [expressionLayout drawAtPoint:NSMakePoint(x, 0)]; x += expressionLayout.bounds.size.width; x += MPParenthesisFunctionClosingParensOffset; NSAffineTransform *transform = [NSAffineTransform transform]; [transform translateXBy:x yBy:0]; [closingParens transformUsingAffineTransform:transform]; [closingParens fill]; } @end