diff --git a/MathKit/MPFunctionLayout.m b/MathKit/MPFunctionLayout.m
old mode 100644
new mode 100755
index 926fd99..c398a7d
--- a/MathKit/MPFunctionLayout.m
+++ b/MathKit/MPFunctionLayout.m
@@ -12,14 +12,18 @@
#import "MPFunction.h"
#import "MPFractionFunction.h"
+#import "MPRootFunction.h"
#import "MPParenthesisFunction.h"
#import "MPPowerFunction.h"
#import "MPSumFunction.h"
+#import "MPProductFunction.h"
#import "MPFractionFunctionLayout.h"
+#import "MPRootFunctionLayout.h"
#import "MPParenthesisFunctionLayout.h"
#import "MPPowerFunctionLayout.h"
#import "MPSumFunctionLayout.h"
+#import "MPProductFunctionLayout.h"
#import "NSIndexPath+MPAdditions.h"
@@ -42,6 +46,10 @@
return [[MPPowerFunctionLayout alloc] initWithFunction:function parent:parent];
} else if (class == [MPFractionFunction class]) {
return [[MPFractionFunctionLayout alloc] initWithFunction:function parent:parent];
+ } else if (class == [MPProductFunction class]) {
+ return [[MPProductFunctionLayout alloc] initWithFunction:function parent:parent];
+ } else if (class == [MPRootFunction class]) {
+ return [[MPRootFunctionLayout alloc] initWithFunction:function parent:parent];
}
return [[self alloc] initWithFunction:function
parent:parent];
diff --git a/MathKit/MPFunctionsViewController.m b/MathKit/MPFunctionsViewController.m
old mode 100644
new mode 100755
index 71008e0..ff58252
--- a/MathKit/MPFunctionsViewController.m
+++ b/MathKit/MPFunctionsViewController.m
@@ -10,9 +10,11 @@
#import "MPFunction.h"
#import "MPFractionFunction.h"
+#import "MPRootFunction.h"
#import "MPParenthesisFunction.h"
#import "MPPowerFunction.h"
#import "MPSumFunction.h"
+#import "MPProductFunction.h"
#import "MPFunctionLayout.h"
@@ -224,16 +226,20 @@ static void *MPFunctionTemplateViewMouseOverContext = @"MPFunctionTemplateViewMo
- (void)awakeFromNib
{
MPFunction *sumFunction = [[MPSumFunction alloc] init];
+ MPFunction *productFunction = [[MPProductFunction alloc] init];
MPFunction *parenthesisFunction = [[MPParenthesisFunction alloc] init];
MPFunction *powerFunction = [[MPPowerFunction alloc] init];
MPPowerFunction *squareFunction = [[MPPowerFunction alloc] init];
squareFunction.exponentExpression = [[MPExpression alloc] initWithElement:@"2"];
MPPowerFunction *cubicFunction = [[MPPowerFunction alloc] init];
cubicFunction.exponentExpression = [[MPExpression alloc] initWithElement:@"3"];
+ MPFunction *rootFunction = [[MPRootFunction alloc] init];
MPFractionFunction *fractionFunction = [[MPFractionFunction alloc] init];
self.functionPrototypes = @[
@{@"function": sumFunction,
@"name": NSLocalizedString(@"Sum", @"Sum Function Name")},
+ @{@"function": productFunction,
+ @"name": NSLocalizedString(@"Product", @"Product Function Name")},
@{@"function": parenthesisFunction,
@"name": NSLocalizedString(@"Parenthesis", @"Parenthesis Function Name")},
@{@"function": squareFunction,
@@ -242,6 +248,8 @@ static void *MPFunctionTemplateViewMouseOverContext = @"MPFunctionTemplateViewMo
@"name": NSLocalizedString(@"Cubic", @"Cubic Function Name")},
@{@"function": powerFunction,
@"name": NSLocalizedString(@"Power", @"Power Function Name")},
+ @{@"function": rootFunction,
+ @"name": NSLocalizedString(@"Root", "Root Function Name")},
@{@"function": fractionFunction,
@"name": NSLocalizedString(@"Fraction", @"Fraction Function Name")}
];
diff --git a/MathKit/MPProductFunction.h b/MathKit/MPProductFunction.h
new file mode 100755
index 0000000..e5ccc5b
--- /dev/null
+++ b/MathKit/MPProductFunction.h
@@ -0,0 +1,70 @@
+//
+// MPProductFunction.h
+// MathPad
+//
+// Created by Kim Wittenburg on 10.01.15.
+// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
+//
+
+#import "MPFunction.h"
+
+
+/*!
+ @header
+ This file contains the MPProductFunction class.
+ */
+
+
+
+@class MPProductFunction, MPExpression;
+
+
+/*!
+ @class MPProductFunction
+ @abstract This class represents a product function (generally noted using a
+ capital pi).
+
+ @discussion A product function has a start and a target expression indicating
+ how often the product expression should be evaluated. Both the
+ value of the start expression and the target expressions are
+ included in the iterations.
+
+ Each iteration the iteration value is incremented by
+ 1. If the start and target expression evaluate to
+ the same value the product is evaluated once.
+ */
+@interface MPProductFunction : MPFunction
+
+/*!
+ @property startExpression
+ @abstract The value of the first iteration.
+
+ @discussion The start expression must define a variable that may be used in
+ the sum expression. If the start expression does not define a
+ variable the product function will not be evaluatable.
+ */
+@property (nonatomic, strong) MPExpression *startExpression; /* Index 0 */
+
+
+/*!
+ @property targetExpression
+ @abstract The value if the last iteration.
+
+ @discussion The target expression must not define a variable.
+ */
+@property (nonatomic, strong) MPExpression *targetExpression; /* Index 1 */
+
+
+/*!
+ @property productExpression
+ @abstract The product expression evaluated multiple times.
+
+ @discussion During evaluation of the product expression the variable defined
+ in the start expression is available. That variable always
+ contains the value of the current iteration.
+
+ The product expression itself must not define a variable.
+ */
+@property (nonatomic, strong) MPExpression *productExpression; /* Index 2 */
+
+@end
diff --git a/MathKit/MPProductFunction.m b/MathKit/MPProductFunction.m
new file mode 100755
index 0000000..07a336b
--- /dev/null
+++ b/MathKit/MPProductFunction.m
@@ -0,0 +1,46 @@
+//
+// MPProductFunction.m
+// MathPad
+//
+// Created by Kim Wittenburg on 10.01.15.
+// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
+//
+
+#import "MPProductFunction.h"
+
+#import "MPProductFunctionTerm.h"
+#import "MPExpression.h"
+
+
+
+@implementation MPProductFunction
+
+MPFunctionAccessorImplementation(StartExpression, _startExpression)
+MPFunctionAccessorImplementation(TargetExpression, _targetExpression)
+MPFunctionAccessorImplementation(ProductExpression, _productExpression)
+
+
+- (NSArray *)childrenAccessors
+{
+ return @[@"startExpression", @"targetExpression", @"productExpression"];
+}
+
+
+- (BOOL)expectsVariableDefinitionInChildAtIndex:(NSUInteger)index
+{
+ return index == 0;
+}
+
+
+- (Class)functionTermClass
+{
+ return [MPProductFunctionTerm class];
+}
+
+
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"Product(From: %@; To: %@; Using: %@)", self.startExpression, self.targetExpression, self.productExpression];
+}
+
+@end
diff --git a/MathKit/MPProductFunctionLayout.h b/MathKit/MPProductFunctionLayout.h
new file mode 100755
index 0000000..a079b84
--- /dev/null
+++ b/MathKit/MPProductFunctionLayout.h
@@ -0,0 +1,35 @@
+//
+// MPProductFunctionLayout.h
+// MathPad
+//
+// Created by Kim Wittenburg on 10.01.15.
+// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
+//
+
+#import "MPFunctionLayout.h"
+
+
+
+@class MPProductFunctionLayout, MPProductFunction;
+
+
+/*!
+ @class MPProductFunctionLayout
+ @abstract A product function layout displays a @link
+ //apple_ref/occ/cl/MPProductFunction@/link.
+
+ @discussion A product is drawn using a capital greeg pi (∏) The three
+ children are placed around it: The start expression below, target
+ expression above and product expression to the right of it.
+ */
+@interface MPProductFunctionLayout : MPFunctionLayout
+
+/*!
+ @method productFunction
+ @abstract Returns the @link
+ //apple_ref/occ/cl/MPProductFunction@/link represented by
+ the receiver.
+ */
+- (MPProductFunction *)productFunction;
+
+@end
diff --git a/MathKit/MPProductFunctionLayout.m b/MathKit/MPProductFunctionLayout.m
new file mode 100755
index 0000000..4a4f77c
--- /dev/null
+++ b/MathKit/MPProductFunctionLayout.m
@@ -0,0 +1,175 @@
+//
+// MPProductFunctionLayout.m
+// MathPad
+//
+// Created by Kim Wittenburg on 10.01.15.
+// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
+//
+
+#import "MPProductFunctionLayout.h"
+
+#import "MPProductFunction.h"
+#import "NSIndexPath+MPAdditions.h"
+
+
+#define kProductFunctionStartExpressionOffset 0
+#define kProductFunctionTargetExpressionOffset 0
+#define kProductFunctionProductExpressionOffset 3
+#define kProductFunctionTrailingOffset 5
+
+
+
+@implementation MPProductFunctionLayout
+
+- (MPProductFunction *)productFunction
+{
+ return (MPProductFunction *)self.function;
+}
+
+
+- (NSUInteger)indexOfLeadingChild
+{
+ return 2;
+}
+
+
+- (NSUInteger)indexOfTrailingChild
+{
+ return 2;
+}
+
+
+- (NSUInteger)indexOfChildAfterChildAtIndex:(NSUInteger)index
+{
+ if (index != 2) {
+ return 2;
+ }
+ return [super indexOfChildAfterChildAtIndex:index];
+}
+
+
+- (NSUInteger)indexOfChildBelowChildAtIndex:(NSUInteger)index
+{
+ return 0;
+}
+
+
+- (NSUInteger)indexOfChildAboveChildAtIndex:(NSUInteger)index
+{
+ return 1;
+}
+
+
+- (NSIndexSet *)indexesOfRemainingChildren
+{
+ return [NSIndexSet indexSetWithIndex:2];
+}
+
+
+- (CTLineRef)line
+{
+ CTLineRef line = [self lineForPrivateCacheIndex:0 generator:^CTLineRef{
+ return [self createLineForString:@"∏"
+ usingFont:[NSFont fontWithName:@"Times New Roman"
+ size:self.contextInferredFontSize]];
+ }];
+ return line;
+}
+
+
+- (NSRect)localLineBounds
+{
+ NSRect lineBounds = CTLineGetBoundsWithOptions(self.line, 0);
+ NSRect startExpressionBounds = [self childLayoutAtIndex:0].bounds;
+ NSRect targetExpressionBounds = [self childLayoutAtIndex:1].bounds;
+ CGFloat width = MAX(MAX(startExpressionBounds.size.width, targetExpressionBounds.size.width), lineBounds.size.width);
+ CGFloat xPosition = (width - lineBounds.size.width) / 2;
+ return NSMakeRect(xPosition, lineBounds.origin.y, lineBounds.size.width, lineBounds.size.height);
+}
+
+
+- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index
+{
+ NSRect childBounds = [self childLayoutAtIndex:index].bounds;
+ NSRect localLineBounds = [self localLineBounds];
+ NSPoint offset;
+ if (index == 0) {
+ // Start Expression
+ offset.x = localLineBounds.origin.x + localLineBounds.size.width / 2 - childBounds.size.width / 2;
+ offset.y = localLineBounds.origin.y - kProductFunctionStartExpressionOffset - childBounds.size.height - childBounds.origin.y;
+ } else if (index == 1) {
+ // Target Expression
+ offset.x = localLineBounds.origin.x + localLineBounds.size.width / 2 - childBounds.size.width / 2;
+ offset.y = kProductFunctionTargetExpressionOffset + localLineBounds.size.height + localLineBounds.origin.y - childBounds.origin.y;
+ } else {
+ // Sum Expression
+ MPLayout *startExpressionLayout = [self childLayoutAtIndex:0];
+ MPLayout *targetExpressionLayout = [self childLayoutAtIndex:1];
+ CGFloat sumWidth = MAX(MAX(localLineBounds.origin.x + localLineBounds.size.width, startExpressionLayout.bounds.size.width), targetExpressionLayout.bounds.size.width);
+ offset.x = sumWidth + kProductFunctionProductExpressionOffset;
+ offset.y = 0;
+ }
+ return offset;
+}
+
+
+- (BOOL)childAtIndexUsesSmallSize:(NSUInteger)index
+{
+ return (index == 0 || index == 1) ? YES : self.usesSmallSize;
+}
+
+
+- (NSIndexPath *)indexPathForLocalMousePoint:(NSPoint)point
+{
+ if (point.x < CTLineGetBoundsWithOptions(self.line, 0).size.width / 2) {
+ return [NSIndexPath indexPathWithIndex:0];
+ } else {
+ return [NSIndexPath indexPathWithIndex:1];
+ }
+}
+
+
+- (NSRect)generateBounds
+{
+ NSRect lineBounds = CTLineGetBoundsWithOptions(self.line, 0);
+ NSRect startExpressionBounds = [self childLayoutAtIndex:0].bounds;
+ NSRect targetExpressionBounds = [self childLayoutAtIndex:1].bounds;
+ NSRect sumExpressionBounds = [self childLayoutAtIndex:2].bounds;
+ NSRect bounds = lineBounds;
+
+ bounds.size.width = MAX(lineBounds.size.width, startExpressionBounds.size.width);
+ bounds.size.height += startExpressionBounds.size.height + kProductFunctionStartExpressionOffset;
+ bounds.origin.y -= startExpressionBounds.size.height + kProductFunctionStartExpressionOffset;
+
+ bounds.size.width = MAX(bounds.size.width, targetExpressionBounds.size.width);
+ bounds.size.height += targetExpressionBounds.size.height + kProductFunctionTargetExpressionOffset;
+
+ bounds.size.width += kProductFunctionProductExpressionOffset + sumExpressionBounds.size.width + kProductFunctionTrailingOffset;
+ CGFloat yOffsetBottom = bounds.origin.y - sumExpressionBounds.origin.y;
+ CGFloat yOffsetTop = sumExpressionBounds.size.height - (yOffsetBottom + bounds.size.height);
+ bounds.size.height = MAX(yOffsetBottom, 0) + bounds.size.height + MAX(yOffsetTop, 0);
+ bounds.origin.y = MIN(sumExpressionBounds.origin.y, bounds.origin.y);
+
+ return bounds;
+}
+
+
+- (void)draw
+{
+ // Get the current context
+ CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+
+ // Set the text matrix
+ CGContextSetTextMatrix(context, CGAffineTransformIdentity);
+
+ // Draw the sum symbol
+ CTLineRef line = [self line];
+ CFRetain(line);
+ NSRect localLineBounds = [self localLineBounds];
+ CGContextSetTextPosition(context, localLineBounds.origin.x, 0);
+ CTLineDraw(line, context);
+
+ CFRelease(line);
+}
+
+@end
diff --git a/MathKit/MPProductFunctionTerm.h b/MathKit/MPProductFunctionTerm.h
new file mode 100755
index 0000000..8b01daf
--- /dev/null
+++ b/MathKit/MPProductFunctionTerm.h
@@ -0,0 +1,37 @@
+//
+// MPProductFunctionTerm.h
+// MathPad
+//
+// Created by Kim Wittenburg on 10.01.15.
+// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
+//
+
+#import "MPFunctionTerm.h"
+
+/*!
+ @header
+ This file contains the MPProductFunctionTerm class.
+ */
+
+
+
+@class MPProductFunctionTerm;
+
+
+/*!
+ @class MPProductFunctionTerm
+ @abstract Represents and evaluates a @link
+ //apple_ref/occ/cl/MPProductFunction@/link.
+
+ @discussion A product function evaluates its sum term n times.
+ How often it actually is evaluated depends on the boundary
+ expressions (start and target). Both are inclusive.
+
+ A product function also features a variable that contains the
+ current value of the iteration. The variable is defined in the
+ start expression and incremented by 1 after every
+ iteration.
+ */
+@interface MPProductFunctionTerm : MPFunctionTerm
+
+@end
diff --git a/MathKit/MPProductFunctionTerm.m b/MathKit/MPProductFunctionTerm.m
new file mode 100755
index 0000000..10ba763
--- /dev/null
+++ b/MathKit/MPProductFunctionTerm.m
@@ -0,0 +1,40 @@
+//
+// MPProductFunctionTerm.m
+// MathPad
+//
+// Created by Kim Wittenburg on 10.01.15.
+// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
+//
+
+#import "MPProductFunctionTerm.h"
+
+#import "MPParsedExpression.h"
+
+
+
+@implementation MPProductFunctionTerm
+
+- (NSDecimalNumber *)doEvaluation:(NSError *__autoreleasing *)error
+{
+ MPParsedExpression *startExpression = [self expressionAtIndex:0];
+ NSDecimalNumber *start = [startExpression evaluate:error];
+ ReturnNilIfNil(start);
+
+ MPEvaluateExpression(target, 1);
+
+ MPParsedExpression *sumExpression = [self expressionAtIndex:2];
+ NSDecimalNumber *value = [NSDecimalNumber one];
+ for (NSDecimalNumber *current = start;
+ [current compare:target] <= 0;
+ current = [current decimalNumberByAdding:[[NSDecimalNumber alloc] initWithInteger:1]]) {
+ if (![self defineVariable:startExpression.definedVariable value:current error:error]) {
+ return nil;
+ }
+ NSDecimalNumber *currentValue = [sumExpression evaluate:error];
+ ReturnNilIfNil(currentValue);
+ value = [value decimalNumberByMultiplyingBy:currentValue];
+ }
+ return value;
+}
+
+@end
diff --git a/MathKit/MPRootFunction.h b/MathKit/MPRootFunction.h
new file mode 100755
index 0000000..1c8a66b
--- /dev/null
+++ b/MathKit/MPRootFunction.h
@@ -0,0 +1,46 @@
+//
+// MPRootFunction.h
+// MathPad
+//
+// Created by Kim Wittenburg on 11.01.15.
+// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
+//
+
+#import "MPFunction.h"
+
+
+/*!
+ @header
+ This file contains the MPRootFunction class.
+ */
+
+
+
+@class MPRootFunction, MPExpression;
+
+
+/*!
+ @class MPRootFunction
+ @abstract This class represents an arbitrary root function.
+
+ @discussion A root has two children: An exponent and the expression to be
+ rooted.
+ */
+@interface MPRootFunction : MPFunction
+
+/*!
+ @property exponentExpression
+ @abstract The receiver's exponent.
+ */
+@property (nonatomic, strong) MPExpression *exponentExpression; /* Index 0 */
+
+
+/*!
+ @property rootExpression
+ @abstract The receiver's root expression.
+
+ @discussion The root expression is the expression that is to be rooted.
+ */
+@property (nonatomic, strong) MPExpression *rootExpression; /* Index 1 */
+
+@end
diff --git a/MathKit/MPRootFunction.m b/MathKit/MPRootFunction.m
new file mode 100755
index 0000000..fe2c6c5
--- /dev/null
+++ b/MathKit/MPRootFunction.m
@@ -0,0 +1,39 @@
+//
+// MPRootFunction.m
+// MathPad
+//
+// Created by Kim Wittenburg on 11.01.15.
+// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
+//
+
+#import "MPRootFunction.h"
+
+#import "MPRootTerm.h"
+#import "MPExpression.h"
+
+
+
+@implementation MPRootFunction
+
+MPFunctionAccessorImplementation(ExponentExpression, _exponentExpression)
+MPFunctionAccessorImplementation(RootExpression, _rootExpression)
+
+
+- (NSArray *)childrenAccessors
+{
+ return @[@"exponentExpression", @"rootExpression"];
+}
+
+
+- (Class)functionTermClass
+{
+ return [MPRootTerm class];
+}
+
+
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"Root(%@, %@)", self.exponentExpression, self.rootExpression];
+}
+
+@end
diff --git a/MathKit/MPRootFunctionLayout.h b/MathKit/MPRootFunctionLayout.h
new file mode 100755
index 0000000..2c0552d
--- /dev/null
+++ b/MathKit/MPRootFunctionLayout.h
@@ -0,0 +1,42 @@
+//
+// MPRootFunctionLayout.h
+// MathPad
+//
+// Created by Kim Wittenburg on 11.01.15.
+// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
+//
+
+#import "MPFunctionLayout.h"
+
+
+/*!
+ @header
+ This file contains the MPRootFunctionLayout class.
+ */
+
+
+
+@class MPRootFunctionLayout, MPRootFunction;
+
+
+/*!
+ @class MPRootFunctionLayout
+ @abstract A root function layout displays a @link
+ //apple_ref/occ/cl/MPRootFunction@/link.
+
+ @discussion A root function is displayed in a very special way. In a way it
+ can be described as an exponent at the left, a "V" in the middle
+ and the expression that is to be rooted at the right with a bar
+ over it.
+ */
+@interface MPRootFunctionLayout : MPFunctionLayout
+
+/*!
+ @method rootFunction
+ @abstract Returns the @link
+ //apple_ref/occ/cl/MPRootFunction@/link represented by the
+ receiver.
+ */
+- (MPRootFunction *)rootFunction;
+
+@end
diff --git a/MathKit/MPRootFunctionLayout.m b/MathKit/MPRootFunctionLayout.m
new file mode 100755
index 0000000..5ceca56
--- /dev/null
+++ b/MathKit/MPRootFunctionLayout.m
@@ -0,0 +1,137 @@
+//
+// MPRootFunctionLayout.m
+// MathPad
+//
+// Created by Kim Wittenburg on 11.01.15.
+// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
+//
+
+#import "MPRootFunctionLayout.h"
+
+#import "MPRootFunction.h"
+
+
+#define kRootFunctionTrailingOffset 3
+
+#define kRootFunctionLineWidth 1
+#define kRootFunctionLineFragmentLength (self.usesSmallSize ? 3 : 4)
+#define kRootFunctionVWidth 5
+
+#define kRootFunctionExpressionXOffset 2
+#define kRootFunctionExponentXInset kRootFunctionLineFragmentLength
+
+
+@implementation MPRootFunctionLayout
+
+- (MPRootFunction *)rootFunction
+{
+ return (MPRootFunction *)self.function;
+}
+
+
+- (NSUInteger)indexOfLeadingChild
+{
+ return 1;
+}
+
+
+- (NSUInteger)indexOfTrailingChild
+{
+ return 1;
+}
+
+
+- (NSUInteger)indexOfChildBelowChildAtIndex:(NSUInteger)index
+{
+ return 1;
+}
+
+
+- (NSUInteger)indexOfChildAboveChildAtIndex:(NSUInteger)index
+{
+ return 0;
+}
+
+
+- (NSUInteger)indexOfChildAfterChildAtIndex:(NSUInteger)index
+{
+ return index == 0 ? 1 : NSNotFound;
+}
+
+
+- (NSIndexSet *)indexesOfRemainingChildren
+{
+ return [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 2)];
+}
+
+
+- (BOOL)childAtIndexUsesSmallSize:(NSUInteger)index
+{
+ return index == 0;
+}
+
+
+- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index
+{
+ NSRect exponentBounds = [self childLayoutAtIndex:0].bounds;
+ NSRect rootBounds = [self childLayoutAtIndex:1].bounds;
+ if (index == 0) {
+ CGFloat x;
+ if (exponentBounds.size.width > kRootFunctionExponentXInset) {
+ x = 0;
+ } else {
+ x = kRootFunctionExponentXInset - exponentBounds.size.width;
+ }
+ return NSMakePoint(x, rootBounds.size.height / 2.0 + rootBounds.origin.y - exponentBounds.origin.y);
+ } else {
+ CGFloat rootSymbolXOffset = exponentBounds.size.width > kRootFunctionExponentXInset ? exponentBounds.size.width - kRootFunctionExponentXInset : 0;
+ CGFloat x = rootSymbolXOffset + kRootFunctionLineFragmentLength + kRootFunctionVWidth + kRootFunctionExpressionXOffset;
+ return NSMakePoint(x, 0);
+ }
+}
+
+
+- (NSIndexPath *)indexPathForLocalMousePoint:(NSPoint)point
+{
+ return [[NSIndexPath indexPathWithIndex:1] indexPathByAddingIndex:0];
+}
+
+- (NSRect)generateBounds
+{
+ CGFloat x, y, width, height;
+ NSRect exponentBounds = [self childLayoutAtIndex:0].bounds;
+ NSRect rootBounds = [self childLayoutAtIndex:1].bounds;
+
+ x = 0;
+ y = rootBounds.origin.y;
+ CGFloat rootSymbolXOffset = exponentBounds.size.width > kRootFunctionLineFragmentLength ? exponentBounds.size.width : kRootFunctionLineFragmentLength;
+ width = rootSymbolXOffset + kRootFunctionVWidth + kRootFunctionExpressionXOffset + rootBounds.size.width + kRootFunctionTrailingOffset;
+ CGFloat heightToExponent = rootBounds.size.height / 2.0 + exponentBounds.size.height;
+ height = MAX(heightToExponent, rootBounds.size.height + kRootFunctionLineWidth);
+ return NSMakeRect(x, y, width, height);
+}
+
+
+- (void)draw
+{
+ NSRect exponentBounds = [self childLayoutAtIndex:0].bounds;
+ NSRect rootBounds = [self childLayoutAtIndex:1].bounds;
+
+ CGFloat rootSymbolXOffset = exponentBounds.size.width > kRootFunctionExponentXInset ? exponentBounds.size.width - kRootFunctionExponentXInset : 0;
+ NSBezierPath *rootPath = [NSBezierPath bezierPath];
+ NSPoint currentPoint = NSMakePoint(rootSymbolXOffset, rootBounds.size.height / 2.0 + rootBounds.origin.y);
+ [rootPath moveToPoint:currentPoint];
+ currentPoint.x += kRootFunctionLineFragmentLength;
+ [rootPath lineToPoint:currentPoint];
+ currentPoint.x += kRootFunctionVWidth / 2.0;
+ currentPoint.y = rootBounds.origin.y;
+ [rootPath lineToPoint:currentPoint];
+ currentPoint.x += kRootFunctionVWidth / 2.0;
+ currentPoint.y = rootBounds.size.height + rootBounds.origin.y;
+ [rootPath lineToPoint:currentPoint];
+ currentPoint.x += rootBounds.size.width;
+ [rootPath lineToPoint:currentPoint];
+ [rootPath stroke];
+}
+
+@end
diff --git a/MathKit/MPRootTerm.h b/MathKit/MPRootTerm.h
new file mode 100755
index 0000000..5edb573
--- /dev/null
+++ b/MathKit/MPRootTerm.h
@@ -0,0 +1,33 @@
+//
+// MPRootTerm.h
+// MathPad
+//
+// Created by Kim Wittenburg on 11.01.15.
+// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
+//
+
+#import "MPFunctionTerm.h"
+
+
+/*!
+ @header
+ This file contains the MPRootTerm class.
+ */
+
+
+
+@class MPRootTerm;
+
+
+/*!
+ @class MPRootTerm
+ @abstract Represents a @link
+ //apple_ref/occ/cl/MPRootFunction@/link.
+
+ @discussion A root function is evaluated by evaluating the power
+ pow(e, 1/n) where e is the expression
+ to be rooted and n the exponent.
+ */
+@interface MPRootTerm : MPFunctionTerm
+
+@end
diff --git a/MathKit/MPRootTerm.m b/MathKit/MPRootTerm.m
new file mode 100755
index 0000000..441724f
--- /dev/null
+++ b/MathKit/MPRootTerm.m
@@ -0,0 +1,44 @@
+//
+// MPRootTerm.m
+// MathPad
+//
+// Created by Kim Wittenburg on 11.01.15.
+// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
+//
+
+#import "MPRootTerm.h"
+
+#import "MPParsedExpression.h"
+
+
+
+@implementation MPRootTerm
+
+- (NSDecimalNumber *)doEvaluation:(NSError *__autoreleasing *)error
+{
+ MPEvaluateExpression(exponent, 0);
+ MPEvaluateExpression(root, 1);
+ if ([root compare:[NSDecimalNumber zero]] < 0) {
+ // There are no negative roots.
+ if (error) {
+ *error = [NSError errorWithDomain:MPMathKitErrorDomain
+ code:101
+ userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"The root of a negative number is undefined.", nil)}];
+ }
+ return nil;
+ }
+ if ([exponent isEqualToNumber:@(0)]) {
+ // The C pow function returns 1 for pow(0, 0). Mathematically this should be undefined.
+ if (error) {
+ *error = [NSError errorWithDomain:MPMathKitErrorDomain
+ code:101
+ userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"The 0th root is undefined.", nil)}];
+ }
+ return nil;
+ }
+ NSDecimalNumber *actualExponent = [[NSDecimalNumber one] decimalNumberByDividingBy:exponent];
+ return [[NSDecimalNumber alloc] initWithDouble:pow(root.doubleValue, actualExponent.doubleValue)];
+
+}
+
+@end
diff --git a/MathPad.xcodeproj/project.pbxproj b/MathPad.xcodeproj/project.pbxproj
old mode 100644
new mode 100755
index ee31b34..f6026b7
--- a/MathPad.xcodeproj/project.pbxproj
+++ b/MathPad.xcodeproj/project.pbxproj
@@ -7,6 +7,16 @@
objects = {
/* Begin PBXBuildFile section */
+ 3B1382E91A65B16200C097B2 /* MPRootFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B1382E71A65B16200C097B2 /* MPRootFunction.h */; };
+ 3B1382EA1A65B16200C097B2 /* MPRootFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B1382E81A65B16200C097B2 /* MPRootFunction.m */; };
+ 3B1382ED1A65B16F00C097B2 /* MPRootTerm.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B1382EB1A65B16F00C097B2 /* MPRootTerm.h */; };
+ 3B1382EE1A65B16F00C097B2 /* MPRootTerm.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B1382EC1A65B16F00C097B2 /* MPRootTerm.m */; };
+ 3B1382F11A65B18200C097B2 /* MPProductFunctionTerm.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B1382EF1A65B18200C097B2 /* MPProductFunctionTerm.h */; };
+ 3B1382F21A65B18200C097B2 /* MPProductFunctionTerm.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B1382F01A65B18200C097B2 /* MPProductFunctionTerm.m */; };
+ 3B1382F51A65B19300C097B2 /* MPProductFunctionLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B1382F31A65B19300C097B2 /* MPProductFunctionLayout.h */; };
+ 3B1382F61A65B19300C097B2 /* MPProductFunctionLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B1382F41A65B19300C097B2 /* MPProductFunctionLayout.m */; };
+ 3B1382F91A65B1A200C097B2 /* MPRootFunctionLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B1382F71A65B1A200C097B2 /* MPRootFunctionLayout.h */; };
+ 3B1382FA1A65B1A200C097B2 /* MPRootFunctionLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B1382F81A65B1A200C097B2 /* MPRootFunctionLayout.m */; };
3B52CEC119BB9FA900CEDCFC /* MathKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B85830D19BB5E5500D76A8D /* MathKit.framework */; };
3B6338351A3A4B5800698BFB /* MPExpression.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B6338321A3A4B5800698BFB /* MPExpression.h */; };
3B6338361A3A4B5800698BFB /* MPExpression.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B6338331A3A4B5800698BFB /* MPExpression.m */; };
@@ -102,6 +112,8 @@
3B85832219BB5E5500D76A8D /* MathKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B85830D19BB5E5500D76A8D /* MathKit.framework */; };
3B85832819BB5E5500D76A8D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3B85832619BB5E5500D76A8D /* InfoPlist.strings */; };
3B85834C19BB661100D76A8D /* MathKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B85833219BB5F2D00D76A8D /* MathKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 3BBD8CDD1A61E35C0042A68B /* MPProductFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BBD8CDB1A61E35C0042A68B /* MPProductFunction.h */; };
+ 3BBD8CDE1A61E35C0042A68B /* MPProductFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBD8CDC1A61E35C0042A68B /* MPProductFunction.m */; };
3BBEA92C19BB680B00133766 /* MathKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3B85830D19BB5E5500D76A8D /* MathKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
3BBEA94F19BB79EF00133766 /* MPExpressionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B0F69AB1902A82C00817707 /* MPExpressionTests.m */; };
3BBEA95019BB79EF00133766 /* MPRangeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBBA3941905704200824E74 /* MPRangeTests.m */; };
@@ -157,6 +169,16 @@
/* Begin PBXFileReference section */
3B0F69AB1902A82C00817707 /* MPExpressionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = MPExpressionTests.m; path = ../MathPadTests/MPExpressionTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
+ 3B1382E71A65B16200C097B2 /* MPRootFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MPRootFunction.h; path = MathKit/MPRootFunction.h; sourceTree = SOURCE_ROOT; };
+ 3B1382E81A65B16200C097B2 /* MPRootFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MPRootFunction.m; path = MathKit/MPRootFunction.m; sourceTree = SOURCE_ROOT; };
+ 3B1382EB1A65B16F00C097B2 /* MPRootTerm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MPRootTerm.h; path = MathKit/MPRootTerm.h; sourceTree = SOURCE_ROOT; };
+ 3B1382EC1A65B16F00C097B2 /* MPRootTerm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MPRootTerm.m; path = MathKit/MPRootTerm.m; sourceTree = SOURCE_ROOT; };
+ 3B1382EF1A65B18200C097B2 /* MPProductFunctionTerm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MPProductFunctionTerm.h; path = MathKit/MPProductFunctionTerm.h; sourceTree = SOURCE_ROOT; };
+ 3B1382F01A65B18200C097B2 /* MPProductFunctionTerm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MPProductFunctionTerm.m; path = MathKit/MPProductFunctionTerm.m; sourceTree = SOURCE_ROOT; };
+ 3B1382F31A65B19300C097B2 /* MPProductFunctionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MPProductFunctionLayout.h; path = MathKit/MPProductFunctionLayout.h; sourceTree = SOURCE_ROOT; };
+ 3B1382F41A65B19300C097B2 /* MPProductFunctionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MPProductFunctionLayout.m; path = MathKit/MPProductFunctionLayout.m; sourceTree = SOURCE_ROOT; };
+ 3B1382F71A65B1A200C097B2 /* MPRootFunctionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MPRootFunctionLayout.h; path = MathKit/MPRootFunctionLayout.h; sourceTree = SOURCE_ROOT; };
+ 3B1382F81A65B1A200C097B2 /* MPRootFunctionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MPRootFunctionLayout.m; path = MathKit/MPRootFunctionLayout.m; sourceTree = SOURCE_ROOT; };
3B6338321A3A4B5800698BFB /* MPExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = MPExpression.h; path = MathKit/MPExpression.h; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
3B6338331A3A4B5800698BFB /* MPExpression.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = MPExpression.m; path = MathKit/MPExpression.m; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
3B6338381A3A4B7600698BFB /* NSString+MPExpressionElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = "NSString+MPExpressionElement.h"; path = "MathKit/NSString+MPExpressionElement.h"; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
@@ -253,6 +275,8 @@
3B85832719BB5E5500D76A8D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
3B85833219BB5F2D00D76A8D /* MathKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = MathKit.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
3BBBA3941905704200824E74 /* MPRangeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = MPRangeTests.m; path = ../MathPadTests/MPRangeTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
+ 3BBD8CDB1A61E35C0042A68B /* MPProductFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MPProductFunction.h; path = MathKit/MPProductFunction.h; sourceTree = SOURCE_ROOT; };
+ 3BBD8CDC1A61E35C0042A68B /* MPProductFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MPProductFunction.m; path = MathKit/MPProductFunction.m; sourceTree = SOURCE_ROOT; };
3BF9976B18DE623E009CF6C4 /* MathPad.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MathPad.app; sourceTree = BUILT_PRODUCTS_DIR; };
3BF9976E18DE623E009CF6C4 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
3BF9977118DE623E009CF6C4 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
@@ -431,12 +455,16 @@
children = (
3B6338541A3A4BE800698BFB /* MPFractionFunction.h */,
3B6338551A3A4BE800698BFB /* MPFractionFunction.m */,
+ 3B1382E71A65B16200C097B2 /* MPRootFunction.h */,
+ 3B1382E81A65B16200C097B2 /* MPRootFunction.m */,
3B63384C1A3A4BD100698BFB /* MPParenthesisFunction.h */,
3B63384D1A3A4BD100698BFB /* MPParenthesisFunction.m */,
3B6338561A3A4BE800698BFB /* MPPowerFunction.h */,
3B6338571A3A4BE800698BFB /* MPPowerFunction.m */,
3B63384E1A3A4BD100698BFB /* MPSumFunction.h */,
3B63384F1A3A4BD100698BFB /* MPSumFunction.m */,
+ 3BBD8CDB1A61E35C0042A68B /* MPProductFunction.h */,
+ 3BBD8CDC1A61E35C0042A68B /* MPProductFunction.m */,
);
name = Functions;
sourceTree = "";
@@ -461,12 +489,16 @@
children = (
3B6338CC1A3A4DE100698BFB /* MPFractionFunctionLayout.h */,
3B6338CD1A3A4DE100698BFB /* MPFractionFunctionLayout.m */,
+ 3B1382F71A65B1A200C097B2 /* MPRootFunctionLayout.h */,
+ 3B1382F81A65B1A200C097B2 /* MPRootFunctionLayout.m */,
3B6338CE1A3A4DE100698BFB /* MPParenthesisFunctionLayout.h */,
3B6338CF1A3A4DE100698BFB /* MPParenthesisFunctionLayout.m */,
3B6338D01A3A4DE100698BFB /* MPPowerFunctionLayout.h */,
3B6338D11A3A4DE100698BFB /* MPPowerFunctionLayout.m */,
3B6338D21A3A4DE100698BFB /* MPSumFunctionLayout.h */,
3B6338D31A3A4DE100698BFB /* MPSumFunctionLayout.m */,
+ 3B1382F31A65B19300C097B2 /* MPProductFunctionLayout.h */,
+ 3B1382F41A65B19300C097B2 /* MPProductFunctionLayout.m */,
);
name = "Function Layouts";
sourceTree = "";
@@ -521,12 +553,16 @@
children = (
3B63389C1A3A4CEF00698BFB /* MPFractionTerm.h */,
3B63389D1A3A4CEF00698BFB /* MPFractionTerm.m */,
+ 3B1382EB1A65B16F00C097B2 /* MPRootTerm.h */,
+ 3B1382EC1A65B16F00C097B2 /* MPRootTerm.m */,
3B6338641A3A4C2B00698BFB /* MPParenthesisTerm.h */,
3B6338651A3A4C2B00698BFB /* MPParenthesisTerm.m */,
3B6338681A3A4C2B00698BFB /* MPPowerTerm.h */,
3B6338691A3A4C2B00698BFB /* MPPowerTerm.m */,
3B6338981A3A4CE100698BFB /* MPSumFunctionTerm.h */,
3B6338991A3A4CE100698BFB /* MPSumFunctionTerm.m */,
+ 3B1382EF1A65B18200C097B2 /* MPProductFunctionTerm.h */,
+ 3B1382F01A65B18200C097B2 /* MPProductFunctionTerm.m */,
);
name = Functions;
sourceTree = "";
@@ -624,6 +660,7 @@
buildActionMask = 2147483647;
files = (
3B6338A81A3A4D2600698BFB /* NSIndexPath+MPAdditions.h in Headers */,
+ 3B1382ED1A65B16F00C097B2 /* MPRootTerm.h in Headers */,
3B85834C19BB661100D76A8D /* MathKit.h in Headers */,
3B63383A1A3A4B7600698BFB /* NSString+MPExpressionElement.h in Headers */,
3B6338C21A3A4DA500698BFB /* MPLayout.h in Headers */,
@@ -633,6 +670,7 @@
3B6338AC1A3A4D3000698BFB /* NSRegularExpression+MPParsingAdditions.h in Headers */,
3B6338501A3A4BD100698BFB /* MPParenthesisFunction.h in Headers */,
3B63387E1A3A4C7E00698BFB /* MPSumTerm.h in Headers */,
+ 3BBD8CDD1A61E35C0042A68B /* MPProductFunction.h in Headers */,
3B6338D81A3A4DE100698BFB /* MPPowerFunctionLayout.h in Headers */,
3B6338801A3A4C7E00698BFB /* MPTerm.h in Headers */,
3B6338521A3A4BD100698BFB /* MPSumFunction.h in Headers */,
@@ -652,17 +690,21 @@
3B63389A1A3A4CE100698BFB /* MPSumFunctionTerm.h in Headers */,
3B6338921A3A4CCA00698BFB /* MPEvaluationContext.h in Headers */,
3B63386C1A3A4C2B00698BFB /* MPNegatedTerm.h in Headers */,
+ 3B1382F91A65B1A200C097B2 /* MPRootFunctionLayout.h in Headers */,
3B63385E1A3A4C0700698BFB /* MPExpressionParser.h in Headers */,
3B63384A1A3A4BB300698BFB /* MPFunction+MPToken.h in Headers */,
3B63383E1A3A4B8500698BFB /* MPToken.h in Headers */,
3B6338461A3A4BA500698BFB /* MPExpressionTokenizer.h in Headers */,
3B63388A1A3A4CAF00698BFB /* MPElementaryFunctionTerm.h in Headers */,
+ 3B1382F51A65B19300C097B2 /* MPProductFunctionLayout.h in Headers */,
3B6338861A3A4CA500698BFB /* MPFactorialTerm.h in Headers */,
+ 3B1382F11A65B18200C097B2 /* MPProductFunctionTerm.h in Headers */,
3B6338581A3A4BE800698BFB /* MPFractionFunction.h in Headers */,
3B6338761A3A4C2B00698BFB /* MPProductTerm.h in Headers */,
3B6338351A3A4B5800698BFB /* MPExpression.h in Headers */,
3B6338BB1A3A4D9400698BFB /* MPFunctionsViewController.h in Headers */,
3B6338D61A3A4DE100698BFB /* MPParenthesisFunctionLayout.h in Headers */,
+ 3B1382E91A65B16200C097B2 /* MPRootFunction.h in Headers */,
3B6338821A3A4C7E00698BFB /* MPVariable.h in Headers */,
3B6338B41A3A4D7900698BFB /* MPExpressionStorage.h in Headers */,
);
@@ -832,6 +874,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 3B1382EE1A65B16F00C097B2 /* MPRootTerm.m in Sources */,
3B6338DB1A3A4DE100698BFB /* MPSumFunctionLayout.m in Sources */,
3B63385F1A3A4C0700698BFB /* MPExpressionParser.m in Sources */,
3B6338A91A3A4D2600698BFB /* NSIndexPath+MPAdditions.m in Sources */,
@@ -842,10 +885,13 @@
3B63389B1A3A4CE100698BFB /* MPSumFunctionTerm.m in Sources */,
3B6338361A3A4B5800698BFB /* MPExpression.m in Sources */,
3B6338BC1A3A4D9400698BFB /* MPFunctionsViewController.m in Sources */,
+ 3B1382F21A65B18200C097B2 /* MPProductFunctionTerm.m in Sources */,
3B63383B1A3A4B7600698BFB /* NSString+MPExpressionElement.m in Sources */,
3B63386D1A3A4C2B00698BFB /* MPNegatedTerm.m in Sources */,
3B6338531A3A4BD100698BFB /* MPSumFunction.m in Sources */,
3B6338A31A3A4CFC00698BFB /* MPRangePath.m in Sources */,
+ 3B1382EA1A65B16200C097B2 /* MPRootFunction.m in Sources */,
+ 3BBD8CDE1A61E35C0042A68B /* MPProductFunction.m in Sources */,
3B63383F1A3A4B8500698BFB /* MPToken.m in Sources */,
3B63389F1A3A4CEF00698BFB /* MPFractionTerm.m in Sources */,
3B6338D71A3A4DE100698BFB /* MPParenthesisFunctionLayout.m in Sources */,
@@ -864,6 +910,8 @@
3B6338BF1A3A4D9400698BFB /* MPWhiteView.m in Sources */,
3B6338931A3A4CCA00698BFB /* MPEvaluationContext.m in Sources */,
3B6338C31A3A4DA500698BFB /* MPLayout.m in Sources */,
+ 3B1382F61A65B19300C097B2 /* MPProductFunctionLayout.m in Sources */,
+ 3B1382FA1A65B1A200C097B2 /* MPRootFunctionLayout.m in Sources */,
3B63387F1A3A4C7E00698BFB /* MPSumTerm.m in Sources */,
3B6338811A3A4C7E00698BFB /* MPTerm.m in Sources */,
3B6338B11A3A4D6A00698BFB /* MPExpressionView.m in Sources */,
diff --git a/MathPad.xcodeproj/project.xcworkspace/xcshareddata/MathPad.xccheckout b/MathPad.xcodeproj/project.xcworkspace/xcshareddata/MathPad.xccheckout
new file mode 100755
index 0000000..35ad05d
--- /dev/null
+++ b/MathPad.xcodeproj/project.xcworkspace/xcshareddata/MathPad.xccheckout
@@ -0,0 +1,41 @@
+
+
+
+
+ IDESourceControlProjectFavoriteDictionaryKey
+
+ IDESourceControlProjectIdentifier
+ 07AABC7B-2194-4C40-BCC8-8DC7EC28F4CC
+ IDESourceControlProjectName
+ MathPad
+ IDESourceControlProjectOriginsDictionary
+
+ 3FA814D5454DEC0D84C2FC10661BDDFF5C0232AB
+ https://bitbucket.org/Codello/mathpad.git
+
+ IDESourceControlProjectPath
+ MathPad.xcodeproj
+ IDESourceControlProjectRelativeInstallPathDictionary
+
+ 3FA814D5454DEC0D84C2FC10661BDDFF5C0232AB
+ ../..
+
+ IDESourceControlProjectURL
+ https://bitbucket.org/Codello/mathpad.git
+ IDESourceControlProjectVersion
+ 111
+ IDESourceControlProjectWCCIdentifier
+ 3FA814D5454DEC0D84C2FC10661BDDFF5C0232AB
+ IDESourceControlProjectWCConfigurations
+
+
+ IDESourceControlRepositoryExtensionIdentifierKey
+ public.vcs.git
+ IDESourceControlWCCIdentifierKey
+ 3FA814D5454DEC0D84C2FC10661BDDFF5C0232AB
+ IDESourceControlWCCName
+ MathPad
+
+
+
+
diff --git a/MathPad.xcodeproj/project.xcworkspace/xcuserdata/Kim.xcuserdatad/WorkspaceSettings.xcsettings b/MathPad.xcodeproj/project.xcworkspace/xcuserdata/Kim.xcuserdatad/WorkspaceSettings.xcsettings
new file mode 100755
index 0000000..bfffcfe
--- /dev/null
+++ b/MathPad.xcodeproj/project.xcworkspace/xcuserdata/Kim.xcuserdatad/WorkspaceSettings.xcsettings
@@ -0,0 +1,10 @@
+
+
+
+
+ HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges
+
+ SnapshotAutomaticallyBeforeSignificantChanges
+
+
+
diff --git a/MathPad.xcodeproj/xcuserdata/kim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/MathPad.xcodeproj/xcuserdata/kim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
new file mode 100755
index 0000000..fe2b454
--- /dev/null
+++ b/MathPad.xcodeproj/xcuserdata/kim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -0,0 +1,5 @@
+
+
+