Archived
1

Added Function Chooser as a Popover

Improved Evaluation
Added Parenthesis Function
This commit is contained in:
Kim Wittenburg
2014-09-28 23:52:29 +02:00
parent 1c8b7e3c12
commit 19a40c2907
16 changed files with 746 additions and 32 deletions

View File

@@ -16,12 +16,17 @@
#import "NSIndexPath+MPAdditions.h"
#import "MPSumFunction.h"
#import "MPParenthesisFunction.h"
#import "MPParenthesisFunctionLayout.h"
#import "MPFunctionsViewController.h"
@interface MPExpressionView ()
@property (nonatomic, weak) NSButton *functionsButton;
@property (nonatomic, strong) NSPopover *functionsPopover;
@property (nonatomic, strong) MPFunctionsViewController *functionsViewController;
@property (nonatomic, strong) NSTimer *caretTimer;
@property (nonatomic) NSTimeInterval caretBlinkRate;
@@ -303,7 +308,7 @@
- (void)initializeExpressionView
{
// Setup the Expression Storage
MPExpressionStorage *expressionStorage = [[MPExpressionStorage alloc] initWithElements:@[@"12345", [[MPSumFunction alloc] init], [[MPSumFunction alloc] init]]];
MPExpressionStorage *expressionStorage = [[MPExpressionStorage alloc] init];
expressionStorage.expressionView = self;
_expressionStorage = expressionStorage;
@@ -347,18 +352,40 @@
self.needsDisplay = YES;
}
- (void)setError:(MPParseError *)error
{
_error = error;
self.needsDisplay = YES;
}
#pragma mark Actions
- (void)showFunctions:(id)sender
{
NSViewController *controller = [[NSViewController alloc] initWithNibName:nil
bundle:nil];
controller.view = [[NSView alloc] init];
NSPopover *popover = [[NSPopover alloc] init];
popover.contentSize = NSMakeSize(100.0, 100.0);
popover.contentViewController = controller;
popover.animates = YES;
popover.behavior = NSPopoverBehaviorSemitransient;
[popover showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxYEdge];
if (self.functionsPopover == nil || self.functionsViewController == nil) {
self.functionsViewController = [[MPFunctionsViewController alloc] init];
self.functionsViewController.target = self;
self.functionsViewController.action = @selector(insertFunction:);
self.functionsPopover = [[NSPopover alloc] init];
self.functionsPopover.contentViewController = self.functionsViewController;
self.functionsPopover.animates = YES;
self.functionsPopover.behavior = NSPopoverBehaviorSemitransient;
}
if (self.functionsPopover.isShown) {
[self.functionsPopover close];
} else {
[self.functionsPopover showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxYEdge];
}
}
- (void)insertFunction:(MPFunction *)function
{
[self.functionsPopover close];
[self.expressionStorage replaceSymbolsInRangePath:self.selection withElements:@[function]];
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
NSIndexPath *functionPath = [self.selection.location indexPathByReplacingLastIndexWithIndex:[targetExpression indexOfElementAtLocation:self.selection.location.lastIndex
offset:NULL]];
MPFunctionLayout *functionLayout = (MPFunctionLayout *)[self.expressionStorage.rootLayout childLayoutAtIndexPath:functionPath];
self.selection = MPMakeRangePath([[functionPath indexPathByAddingIndex:functionLayout.indexOfLeadingChild] indexPathByAddingIndex:0], 0);
}
#pragma mark NSView Stuff
@@ -372,6 +399,20 @@
return YES;
}
- (BOOL)becomeFirstResponder
{
[self restartCaretTimer];
return [super becomeFirstResponder];
}
- (BOOL)resignFirstResponder
{
[self.caretTimer invalidate];
self.caretVisible = NO;
self.needsDisplay = YES;
return [super resignFirstResponder];
}
- (BOOL)isFlipped
{
return NO;
@@ -415,17 +456,40 @@
- (void)keyDown:(NSEvent *)theEvent
{
NSString *characters = theEvent.characters;
if ([characters isEqualToString:@"("]) {
[self insertParenthesisFunction];
return;
}
NSString *decimalSeparator = [NSRegularExpression escapedPatternForString:[[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]];
NSMutableCharacterSet *allowedCharacters = [NSMutableCharacterSet alphanumericCharacterSet];
[allowedCharacters addCharactersInString:@"+-*= "];
[allowedCharacters addCharactersInString:[NSString stringWithFormat:@"+-*= %@", decimalSeparator]];
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.expressionStorage replaceSymbolsInRangePath:self.selection withElements:@[characters]];
self.selection = MPMakeRangePath([self.selection.location indexPathByIncrementingLastIndex], 0);
} else {
[self interpretKeyEvents:@[theEvent]];
}
}
- (void)insertParenthesisFunction
{
MPExpression *selectedElementsExpression = [self.expressionStorage subexpressionWithRangePath:self.selection];
MPParenthesisFunction *function = [[MPParenthesisFunction alloc] init];
function.expression = selectedElementsExpression;
[self.expressionStorage replaceSymbolsInRangePath:self.selection
withElements:@[function]];
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
NSIndexPath *functionPath = [self.selection.location indexPathByReplacingLastIndexWithIndex:[targetExpression indexOfElementAtLocation:self.selection.location.lastIndex
offset:NULL]];
self.selection = MPMakeRangePath([[functionPath indexPathByAddingIndex:0] indexPathByAddingIndex:0], self.selection.length);
}
- (void)insertNewline:(id)sender
{
if (self.target && self.action) {
@@ -571,6 +635,30 @@
self.selection = MPMakeRangePath(location, maxLocation.lastIndex-location.lastIndex);
}
- (void)moveUp:(id)sender
{
NSIndexPath *targetExpressionPath = [self.selection.location indexPathByRemovingLastIndex];
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:targetExpressionPath];
if (targetExpression.parent != nil) {
NSIndexPath *functionPath = [targetExpressionPath indexPathByRemovingLastIndex];
MPFunctionLayout *functionLayout = (MPFunctionLayout *)[self.expressionStorage.rootLayout childLayoutAtIndexPath:functionPath];
NSUInteger newChildIndex = [functionLayout indexOfChildAboveChildAtIndex:targetExpressionPath.lastIndex];
self.selection = MPMakeRangePath([[targetExpressionPath indexPathByReplacingLastIndexWithIndex:newChildIndex] indexPathByAddingIndex:0], 0);
}
}
- (void)moveDown:(id)sender
{
NSIndexPath *targetExpressionPath = [self.selection.location indexPathByRemovingLastIndex];
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:targetExpressionPath];
if (targetExpression.parent != nil) {
NSIndexPath *functionPath = [targetExpressionPath indexPathByRemovingLastIndex];
MPFunctionLayout *functionLayout = (MPFunctionLayout *)[self.expressionStorage.rootLayout childLayoutAtIndexPath:functionPath];
NSUInteger newChildIndex = [functionLayout indexOfChildBelowChildAtIndex:targetExpressionPath.lastIndex];
self.selection = MPMakeRangePath([[targetExpressionPath indexPathByReplacingLastIndexWithIndex:newChildIndex] indexPathByAddingIndex:0], 0);
}
}
- (void)selectAll:(id)sender
{
NSIndexPath *location = [NSIndexPath indexPathWithIndex:0];
@@ -579,13 +667,42 @@
- (void)deleteBackward:(id)sender
{
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
if (self.selection.length > 0) {
[targetExpression replaceSymbolsInRange:self.selection.rangeAtLastIndex withElements:@[]];
[self.expressionStorage replaceSymbolsInRangePath:self.selection withElements:@[]];
self.selection = MPMakeRangePath(self.selection.location, 0);
} else if (self.selection.location.lastIndex > 0) {
[targetExpression replaceSymbolsInRange:NSMakeRange(self.selection.location.lastIndex-1, 1) withElements:@[]];
self.selection = MPMakeRangePath([self.selection.location indexPathByDecrementingLastIndex], 0);
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
id <MPExpressionElement> elementToDelete = [targetExpression elementAtIndex:[targetExpression indexOfElementAtLocation:self.selection.location.lastIndex-1
offset:NULL]];
if ([elementToDelete isFunction]) {
self.selection = MPMakeRangePath(self.selection.location.indexPathByDecrementingLastIndex, 1);
} else {
[targetExpression replaceSymbolsInRange:NSMakeRange(self.selection.location.lastIndex-1, 1) withElements:@[]];
self.selection = MPMakeRangePath([self.selection.location indexPathByDecrementingLastIndex], 0);
}
} else {
NSIndexPath *targetExpressionPath = [self.selection.location indexPathByRemovingLastIndex];
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:targetExpressionPath];
if (targetExpression.parent != nil) {
NSIndexPath *functionPath = [targetExpressionPath indexPathByRemovingLastIndex];
MPFunction *function = [self.expressionStorage elementAtIndexPath:functionPath];
MPFunctionLayout *functionLayout = (MPFunctionLayout *)[self.expressionStorage.rootLayout childLayoutAtIndexPath:functionPath];
NSIndexSet *remainingIndexes = [functionLayout indexesOfRemainingChildren];
NSMutableArray *remainder = [[NSMutableArray alloc] init];
for (NSUInteger index = remainingIndexes.firstIndex;
index <= remainingIndexes.lastIndex;
index = [remainingIndexes indexGreaterThanIndex:index]) {
[remainder addObjectsFromArray:[function childAtIndex:index].elements];
}
NSIndexPath *newTargetExpressionPath = [functionPath indexPathByRemovingLastIndex];
MPExpression *newTargetExpression = [self.expressionStorage elementAtIndexPath:newTargetExpressionPath];
NSIndexPath *newSelectionLocation = [functionPath indexPathByReplacingLastIndexWithIndex:[newTargetExpression locationOfElementAtIndex:functionPath.lastIndex]];
[self.expressionStorage replaceSymbolsInRangePath:MPMakeRangePath(functionPath, 1) withElements:remainder];
self.selection = MPMakeRangePath(newSelectionLocation, 0);
}
}
}
@@ -626,6 +743,11 @@
// Calculate the position of the expression (probably also forces layout of the expression the first time)
NSPoint expressionOrigin = self.expressionOrigin;
NSAffineTransform *transform = [NSAffineTransform transform];
[transform translateXBy:expressionOrigin.x
yBy:expressionOrigin.y];
[transform concat];
// Draw the selection
if (self.caretVisible || self.selection.length > 0) {
if (self.selection.length == 0) {
@@ -633,15 +755,12 @@
} else {
[[NSColor selectedTextBackgroundColor] set];
}
NSAffineTransform *transform = [NSAffineTransform transform];
[transform translateXBy:expressionOrigin.x
yBy:expressionOrigin.y];
[transform concat];
NSRectFill([self selectionRect]);
[transform invert];
[transform concat];
}
[transform invert];
[transform concat];
// Draw the expression
[[NSColor textColor] set];
[self.expressionStorage.rootLayout drawAtPoint:expressionOrigin];