From a69b5273ee29134dad685853b5d3d19a404cc709 Mon Sep 17 00:00:00 2001 From: Kim Wittenburg Date: Sat, 6 Sep 2014 01:53:22 +0200 Subject: [PATCH] Started to Implement Evaluation Corrected Some Errors Cleaned Code --- MathPad/Base.lproj/MPDocument.xib | 23 ++++++++++++---- MathPad/MPDocument.h | 3 +-- MathPad/MPDocument.m | 9 ++++--- MathPad/MPExpression.h | 42 ++++++++++++++++------------- MathPad/MPExpression.m | 44 ++++++++++++++++++++----------- MathPad/MPExpressionLayout.m | 11 -------- MathPad/MPExpressionView.m | 23 ++++++++++------ MathPad/MPFunction.h | 4 +-- MathPad/MPFunction.m | 5 ++-- MathPad/MPLayout.h | 2 ++ MathPad/MPLayout.m | 41 ++++++++-------------------- MathPad/MPSumFunction.m | 4 +-- MathPad/MPSumFunctionLayout.m | 8 +----- 13 files changed, 112 insertions(+), 107 deletions(-) diff --git a/MathPad/Base.lproj/MPDocument.xib b/MathPad/Base.lproj/MPDocument.xib index 0a691eb..dbf8825 100644 --- a/MathPad/Base.lproj/MPDocument.xib +++ b/MathPad/Base.lproj/MPDocument.xib @@ -22,15 +22,28 @@ - + + - - - - + + + + + + diff --git a/MathPad/MPDocument.h b/MathPad/MPDocument.h index 927eff2..6b69ad2 100644 --- a/MathPad/MPDocument.h +++ b/MathPad/MPDocument.h @@ -10,9 +10,8 @@ @interface MPDocument : NSDocument -@property (weak) IBOutlet MPExpressionView *termExpressionView; @property (weak) IBOutlet MPExpressionView *resultExpressionView; -- (IBAction)changeExpression:(id)sender; +- (IBAction)evaluateExpressiom:(id)sender; @end diff --git a/MathPad/MPDocument.m b/MathPad/MPDocument.m index aa4ee62..f06ef47 100644 --- a/MathPad/MPDocument.m +++ b/MathPad/MPDocument.m @@ -7,7 +7,6 @@ // #import "MPDocument.h" -#import "MPModel.h" #import "MPView.h" @implementation MPDocument @@ -59,8 +58,12 @@ } #pragma mark Actions -- (IBAction)changeExpression:(id)sender { - [self.resultExpressionView.expressionStorage insertElement:@"abc" atLocation:6]; +- (IBAction)evaluateExpressiom:(id)sender { + NSError *error; + NSLog(@"Result: %f", [self.resultExpressionView.expressionStorage evaluateExpression:&error]); + if (error) { + NSLog(@"Error: %@", error); + } } @end diff --git a/MathPad/MPExpression.h b/MathPad/MPExpression.h index 8a9f9e9..6862649 100644 --- a/MathPad/MPExpression.h +++ b/MathPad/MPExpression.h @@ -9,7 +9,7 @@ @import Foundation; #import "NSString+MPExpressionElement.h" -@class MPExpression, MPFunction, MPRangePath; +@class MPExpression, MPFunction, MPRangePath, MPExpressionEvaluator; @protocol MPExpressionElement; /*! @@ -269,8 +269,26 @@ - (void)replaceSymbolsInRange:(NSRange)range withElements:(NSArray *)elements; -#warning Evaluating must possibly return error -- (double)doubleValue; // Evaluates Expression + +/*! + @method elements + @brief Returns an array of all elements in the receiver. + + @discussion The elements in the returned array are not copied before they are + returned. + + @return An array of all elements from the receiver. + */ +- (NSArray *)elements; + + +#pragma mark Evaluating Expressions + +- (double)evaluateExpression:(NSError *__autoreleasing *)error; + + +// TODO: Private? +@property (readonly, nonatomic, strong) MPExpressionEvaluator *evaluator; #pragma mark Notifications // All notification methods should create a new rangePath with the receiver's index added to the beginning of the path and then ascend the message to it's parent @@ -312,7 +330,7 @@ @return @c YES if @c anExpression is equal to the receiver, @c NO otherwise. */ -- (BOOL)isEqualToExpression:(MPExpression *)anExpression; +// - (BOOL)isEqualToExpression:(MPExpression *)anExpression; - (NSString *)description; - (NSUInteger)hash; @@ -534,21 +552,6 @@ - (void)deleteElementsInRange:(NSRange)range; -#pragma mark Querying Expressions - - -/*! - @method elements - @brief Returns an array of all elements in the receiver. - - @discussion The elements in the returned array are not copied before they are - returned. - - @return An array of all elements from the receiver. - */ -- (NSArray *)elements; - - /*! @method mutableElements @brief Returns a proxy mutable array object that responds to all methods @@ -564,3 +567,4 @@ // - (NSMutableArray *)mutableElements; @end + diff --git a/MathPad/MPExpression.m b/MathPad/MPExpression.m index cc22c52..bdae3f7 100644 --- a/MathPad/MPExpression.m +++ b/MathPad/MPExpression.m @@ -6,6 +6,8 @@ // Copyright (c) 2014 Kim Wittenburg. All rights reserved. // +// TODO: Reorganise header/implementation order. Drop the primitive/not primitive Approach + #import "MPExpression.h" #import "MPFunction.h" #import "MPRangePath.h" @@ -13,8 +15,11 @@ #import "NSIndexPath+MPAdditions.h" #import "MPException.h" -@interface MPExpression () -@property (readonly, nonatomic, strong) NSMutableArray *elements; +#import "MPExpressionEvaluator.h" + +@interface MPExpression () { + NSMutableArray *__strong _elements; +} @end @interface MPExpression (MPExpressionPrivate) @@ -64,8 +69,8 @@ NSString *splitElement = (NSString *)self.elements[splitElementIndex]; NSString *leftPart = [splitElement substringToIndex:splitOffset]; NSString *rightPart = [splitElement substringFromIndex:splitOffset]; - [self.elements replaceObjectsInRange:NSMakeRange(splitElementIndex, 1) - withObjectsFromArray:@[leftPart, rightPart]]; + [_elements replaceObjectsInRange:NSMakeRange(splitElementIndex, 1) + withObjectsFromArray:@[leftPart, rightPart]]; ++splitElementIndex; } *insertionIndex = splitElementIndex; @@ -81,8 +86,6 @@ NSUInteger _replacementLength; } -@synthesize elements = _elements; - #pragma mark Creation Methods - (instancetype)init { @@ -114,14 +117,14 @@ id current = self.elements[index]; if ([current isString]) { if (current.length == 0) { - [self.elements removeObjectAtIndex:index]; + [_elements removeObjectAtIndex:index]; if (index >= _editedRange.location && index < NSMaxRange(_editedRange)) { --_replacementLength; } --index; } else if ([next isString]) { NSString *new = [NSString stringWithFormat:@"%@%@", current, next]; - [self.elements replaceObjectsInRange:NSMakeRange(index, 2) + [_elements replaceObjectsInRange:NSMakeRange(index, 2) withObjectsFromArray:@[new]]; NSUInteger maxReplacementIndex = _editedRange.location + _replacementLength; if (index == _editedRange.location - 1) { @@ -244,7 +247,7 @@ // Perform the replacement NSMutableArray *newElements = [[NSMutableArray alloc] initWithArray:elements copyItems:YES]; - [self.elements replaceObjectsInRange:NSMakeRange(startIndex, endIndex-startIndex) + [_elements replaceObjectsInRange:NSMakeRange(startIndex, endIndex-startIndex) withObjectsFromArray:newElements]; _cachedLength = 0; @@ -260,11 +263,23 @@ replacementLength:_replacementLength]; } - -- (double)doubleValue +- (NSArray *)elements { -#warning Unimplemented Method - return 0; + return _elements; +} + +- (double)evaluateExpression:(NSError *__autoreleasing *)error +{ + return [self.evaluator evaluateWithError:error]; +} + +@synthesize evaluator = _evaluator; +- (MPExpressionEvaluator *)evaluator +{ + if (!_evaluator) { + _evaluator = [[MPExpressionEvaluator alloc] initWithExpression:self]; + } + return _evaluator; } #pragma mark Notifications @@ -272,8 +287,7 @@ replacementLength:(NSUInteger)replacementLength { NSUInteger selfIndex = [self.parent indexOfChild:self]; - MPRangePath *newPath = rangePath.copy; - newPath.location = [newPath.location indexPathByPreceedingIndex:selfIndex]; + MPRangePath *newPath = MPMakeRangePath([rangePath.location indexPathByPreceedingIndex:selfIndex], rangePath.length); [self.parent didChangeElementsInRangePath:newPath replacementLength:replacementLength]; } diff --git a/MathPad/MPExpressionLayout.m b/MathPad/MPExpressionLayout.m index baa4e9d..0ae3c52 100644 --- a/MathPad/MPExpressionLayout.m +++ b/MathPad/MPExpressionLayout.m @@ -16,7 +16,6 @@ @interface MPExpressionLayout (MPLineGeneration) - (CTLineRef)lineForElementAtIndex:(NSUInteger)index; -- (CTLineRef)createLineForString:(NSString *)aString; @end @@ -36,16 +35,6 @@ return (__bridge CTLineRef)lineObject; } -- (CTLineRef)createLineForString:(NSString *)aString -{ - NSAttributedString *text = [[NSAttributedString alloc] initWithString:aString - attributes:@{NSFontAttributeName: self.font}]; - CFAttributedStringRef attributedString = CFBridgingRetain(text); - CTLineRef line = CTLineCreateWithAttributedString(attributedString); - CFRelease(attributedString); // TODO: Is this release appropriate? - return line; -} - @end @implementation MPExpressionLayout diff --git a/MathPad/MPExpressionView.m b/MathPad/MPExpressionView.m index 6a40209..0624075 100644 --- a/MathPad/MPExpressionView.m +++ b/MathPad/MPExpressionView.m @@ -51,7 +51,7 @@ { NSRect expressionBounds = [self.expressionStorage.rootLayout bounds]; CGFloat y = (self.bounds.size.height - expressionBounds.size.height) / 2 + fabs(expressionBounds.origin.y); - return NSMakePoint(self.bounds.origin.x, self.bounds.origin.y + y); + return NSMakePoint(0, y); } @end @@ -124,15 +124,19 @@ - (void)initializeExpressionView { + // Setup the Expression Storage MPExpressionStorage *expressionStorage = [[MPExpressionStorage alloc] initWithElements:@[@"12345", [[MPSumFunction alloc] init], [[MPSumFunction alloc] init]]]; expressionStorage.expressionView = self; _expressionStorage = expressionStorage; - NSRect frame = NSMakeRect(10, 10, 500, 500); - NSButton *button = [[NSButton alloc] initWithFrame:frame]; + + // Setup the Functions Button + NSButton *button = [[NSButton alloc] initWithFrame:NSZeroRect]; button.buttonType = NSSwitchButton; [button setTitle:@"Functions"]; self.functionsButton = button; [self addSubview:self.functionsButton]; + + // Setup Selection self.selection = [[MPRangePath alloc] initWithRange:NSMakeRange(0, 0)]; self.caretBlinkRate = 1.0; [self restartCaretTimer]; @@ -202,7 +206,9 @@ - (void)keyDown:(NSEvent *)theEvent { NSString *characters = theEvent.characters; - if (characters.length == 1 && [characters stringByTrimmingCharactersInSet:[NSCharacterSet decimalDigitCharacterSet]].length == 0) { + NSMutableCharacterSet *allowedCharacters = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedCharacters addCharactersInString:@"+-*/= "]; + if (characters.length == 1 && [characters stringByTrimmingCharactersInSet:allowedCharacters].length == 0) { MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]]; [targetExpression replaceSymbolsInRange:self.selection.rangeAtLastIndex withElements:@[characters]]; self.selection = MPMakeRangePath([self.selection.location indexPathByIncrementingLastIndex], 0); @@ -277,7 +283,8 @@ - (void)moveToEndOfLine:(id)sender { - + MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]]; + self.selection = MPMakeRangePath([self.selection.location indexPathByReplacingLastIndexWithIndex:targetExpression.length], 0); } - (void)moveLeftAndModifySelection:(id)sender @@ -317,12 +324,12 @@ - (void)moveWordRightAndModifySelection:(id)sender { - +#warning Unimplemented Method } - (void)moveWordLeftAndModifySelection:(id)sender { - +#warning Unimplemented Method } - (void)selectAll:(id)sender @@ -361,7 +368,7 @@ // Draw the background [super drawRect:dirtyRect]; [[NSColor whiteColor] set]; - NSRectFill(self.bounds); + NSRectFill(dirtyRect); // Calculate the position of the expression (probably also forces layout of the expression the first time) NSPoint expressionOrigin = self.expressionOrigin; diff --git a/MathPad/MPFunction.h b/MathPad/MPFunction.h index bba4431..ca7ca9c 100644 --- a/MathPad/MPFunction.h +++ b/MathPad/MPFunction.h @@ -37,7 +37,7 @@ - (id)elementAtIndexPath:(NSIndexPath *)indexPath; #pragma mark Evaluating Functions -- (double)doubleValue; // Override +- (double)evaluateFunction:(NSError *__autoreleasing *)error; #pragma mark Messages - (void)didChangeElementsInRangePath:(MPRangePath *)rangePath @@ -46,7 +46,7 @@ - (void)didChangeChildAtIndex:(NSUInteger)index; #pragma mark Working With Functions -- (BOOL)isEqualToFunction:(MPFunction *)aFunction; // Override +// - (BOOL)isEqualToFunction:(MPFunction *)aFunction; // Override - (NSString *)description; // Should be overridden - (NSUInteger)hash;// Override diff --git a/MathPad/MPFunction.m b/MathPad/MPFunction.m index bd3b02d..c70f8d4 100644 --- a/MathPad/MPFunction.m +++ b/MathPad/MPFunction.m @@ -82,7 +82,7 @@ } #pragma mark Evaluating Functions -- (double)doubleValue +- (double)evaluateFunction:(NSError *__autoreleasing *)error { return 0; } @@ -92,8 +92,7 @@ replacementLength:(NSUInteger)replacementLength { NSUInteger selfIndex = [self.parent indexOfElement:self]; - MPRangePath *newPath = rangePath.copy; - newPath.location = [newPath.location indexPathByPreceedingIndex:selfIndex]; + MPRangePath *newPath = MPMakeRangePath([rangePath.location indexPathByPreceedingIndex:selfIndex], rangePath.length); [self.parent didChangeElementsInRangePath:newPath replacementLength:replacementLength]; } diff --git a/MathPad/MPLayout.h b/MathPad/MPLayout.h index a341e74..26cb9b6 100644 --- a/MathPad/MPLayout.h +++ b/MathPad/MPLayout.h @@ -41,6 +41,8 @@ - (void)invalidate; #pragma mark Calculation and Drawing Methods +- (CTLineRef)createLineForString:(NSString *)aString; + @property (nonatomic, getter = isFlipped) BOOL flipped; @property (nonatomic) BOOL usesSmallSize; - (NSRect)bounds; diff --git a/MathPad/MPLayout.m b/MathPad/MPLayout.m index 22768e8..49b5b4f 100644 --- a/MathPad/MPLayout.m +++ b/MathPad/MPLayout.m @@ -128,6 +128,16 @@ } #pragma mark Calculation and Drawing Methods +- (CTLineRef)createLineForString:(NSString *)aString +{ + NSAttributedString *text = [[NSAttributedString alloc] initWithString:aString + attributes:@{NSFontAttributeName: self.font}]; + CFAttributedStringRef attributedString = CFBridgingRetain(text); + CTLineRef line = CTLineCreateWithAttributedString(attributedString); + CFRelease(attributedString); // TODO: Is this release appropriate? + return line; +} + - (NSRect)bounds { if (NSEqualRects(_cachedBounds, NSZeroRect)) { @@ -161,33 +171,4 @@ [transform concat]; } -@end - -@implementation MPLayout (MPSubclassImplement) - -- (MPLayout *)childLayoutAtIndex:(NSUInteger)index -{ - return nil; -} - -- (NSRect)generateBounds -{ - return NSZeroRect; -} - -- (NSRect)boundingRectForRange:(NSRange)range -{ - return NSZeroRect; -} - -- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index -{ - return NSZeroPoint; -} - -- (void)draw -{ - -} - -@end +@end \ No newline at end of file diff --git a/MathPad/MPSumFunction.m b/MathPad/MPSumFunction.m index e267d2c..6b649f5 100644 --- a/MathPad/MPSumFunction.m +++ b/MathPad/MPSumFunction.m @@ -97,10 +97,10 @@ } #pragma mark Evaluating Functions -- (double)doubleValue +- (double)evaluateFunction:(NSError *__autoreleasing *)error { #warning Unimplemented Method - return 0; + return 0.0; } #pragma mark Working With Functions diff --git a/MathPad/MPSumFunctionLayout.m b/MathPad/MPSumFunctionLayout.m index 887f2b7..b30de11 100644 --- a/MathPad/MPSumFunctionLayout.m +++ b/MathPad/MPSumFunctionLayout.m @@ -26,13 +26,7 @@ - (CTLineRef)line { CTLineRef line = [self lineForPrivateCacheIndex:0 generator:^CTLineRef{ - NSAttributedString *text = - [[NSAttributedString alloc] initWithString:@"∑" - attributes:@{NSFontAttributeName: self.font}]; - CFAttributedStringRef attributedString = CFBridgingRetain(text); - CTLineRef line = CTLineCreateWithAttributedString(attributedString); - CFRelease(attributedString); // TODO: Is this release appropriate - return line; + return [self createLineForString:@"∑"]; }]; return line; }