Added Function Chooser as a Popover
Improved Evaluation Added Parenthesis Function
This commit is contained in:
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user