Removed Deg/Rad Button, Replaced with Menu Actions
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
#import "MPExpressionView.h"
|
#import "MPExpressionView.h"
|
||||||
|
|
||||||
#import "MPExpression.h"
|
#import "MPExpression.h"
|
||||||
#import "MPExpressionElement.h"
|
#import "MPExpression.h"
|
||||||
#import "MPParsedExpression.h"
|
#import "MPParsedExpression.h"
|
||||||
|
|
||||||
#import "MPPowerFunction.h"
|
#import "MPPowerFunction.h"
|
||||||
@@ -30,8 +30,6 @@
|
|||||||
|
|
||||||
@interface MPExpressionView ()
|
@interface MPExpressionView ()
|
||||||
|
|
||||||
@property (nonatomic, strong) NSButton *radiansDegreesButton;
|
|
||||||
|
|
||||||
@property (nonatomic, strong) NSButton *functionsButton;
|
@property (nonatomic, strong) NSButton *functionsButton;
|
||||||
@property (nonatomic, strong) NSPopover *functionsPopover;
|
@property (nonatomic, strong) NSPopover *functionsPopover;
|
||||||
@property (nonatomic, strong) MPFunctionsViewController *functionsViewController;
|
@property (nonatomic, strong) MPFunctionsViewController *functionsViewController;
|
||||||
@@ -59,7 +57,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@interface MPExpressionView (MPSelection)
|
@interface MPExpressionView (MPSelectionHelper)
|
||||||
- (void)restartCaretTimer;
|
- (void)restartCaretTimer;
|
||||||
- (void)updateCaret:(NSTimer *)timer;
|
- (void)updateCaret:(NSTimer *)timer;
|
||||||
|
|
||||||
@@ -91,7 +89,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation MPExpressionView (MPSelection)
|
@implementation MPExpressionView (MPSelectionHelper)
|
||||||
|
|
||||||
- (void)restartCaretTimer
|
- (void)restartCaretTimer
|
||||||
{
|
{
|
||||||
@@ -313,6 +311,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
@implementation MPExpressionView
|
@implementation MPExpressionView
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
#pragma mark Creation Methods
|
||||||
@@ -351,21 +350,10 @@
|
|||||||
|
|
||||||
- (void)initializeButtons
|
- (void)initializeButtons
|
||||||
{
|
{
|
||||||
NSButton *radiansDegreesButton = self.radiansDegreesButton;
|
|
||||||
[self addSubview:radiansDegreesButton];
|
|
||||||
NSButton *functionsButton = self.functionsButton;
|
NSButton *functionsButton = self.functionsButton;
|
||||||
[self addSubview:functionsButton];
|
[self addSubview:functionsButton];
|
||||||
|
|
||||||
NSDictionary *variableBindings = NSDictionaryOfVariableBindings(radiansDegreesButton, functionsButton);
|
NSDictionary *variableBindings = NSDictionaryOfVariableBindings(functionsButton);
|
||||||
|
|
||||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[radiansDegreesButton]"
|
|
||||||
options:0
|
|
||||||
metrics:nil
|
|
||||||
views:variableBindings]];
|
|
||||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[radiansDegreesButton]"
|
|
||||||
options:0
|
|
||||||
metrics:nil
|
|
||||||
views:variableBindings]];
|
|
||||||
|
|
||||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[functionsButton]-10-|"
|
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[functionsButton]-10-|"
|
||||||
options:0
|
options:0
|
||||||
@@ -406,7 +394,56 @@
|
|||||||
views:variableBindings]];
|
views:variableBindings]];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Properties
|
#pragma mark - NSView Configuration
|
||||||
|
- (BOOL)acceptsFirstResponder
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canBecomeKeyView
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isOpaque
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resetCursorRects
|
||||||
|
{
|
||||||
|
[self addCursorRect:self.bounds
|
||||||
|
cursor:[NSCursor IBeamCursor]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)becomeFirstResponder
|
||||||
|
{
|
||||||
|
[self restartCaretTimer];
|
||||||
|
return [super becomeFirstResponder];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)resignFirstResponder
|
||||||
|
{
|
||||||
|
[self.caretTimer invalidate];
|
||||||
|
self.caretVisible = NO;
|
||||||
|
self.needsDisplay = YES;
|
||||||
|
return [super resignFirstResponder];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFrame:(NSRect)frameRect
|
||||||
|
{
|
||||||
|
[self setNeedsLayout:YES];
|
||||||
|
[super setFrame:frameRect];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSSize)intrinsicContentSize
|
||||||
|
{
|
||||||
|
NSSize size = self.expressionStorage.rootLayout.bounds.size;
|
||||||
|
size.width += 100;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Properties
|
||||||
- (void)setExpressionStorage:(MPExpressionStorage *)expressionStorage
|
- (void)setExpressionStorage:(MPExpressionStorage *)expressionStorage
|
||||||
{
|
{
|
||||||
_expressionStorage.expressionView = nil;
|
_expressionStorage.expressionView = nil;
|
||||||
@@ -460,25 +497,6 @@
|
|||||||
self.mathErrorTextField.stringValue = mathError != nil ? mathError.localizedDescription : @"";
|
self.mathErrorTextField.stringValue = mathError != nil ? mathError.localizedDescription : @"";
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSButton *)radiansDegreesButton
|
|
||||||
{
|
|
||||||
if (!_radiansDegreesButton) {
|
|
||||||
NSButton *radiansDegreesButton = [[NSButton alloc] initWithFrame:NSZeroRect];
|
|
||||||
radiansDegreesButton.translatesAutoresizingMaskIntoConstraints = NO;
|
|
||||||
radiansDegreesButton.buttonType = NSMomentaryPushInButton;
|
|
||||||
radiansDegreesButton.bordered = YES;
|
|
||||||
radiansDegreesButton.bezelStyle = NSRoundedBezelStyle;
|
|
||||||
radiansDegreesButton.imagePosition = NSNoImage;
|
|
||||||
radiansDegreesButton.alignment = NSCenterTextAlignment;
|
|
||||||
radiansDegreesButton.title = NSLocalizedString([MPMathRules sharedRules].isUsingDegrees ? @"Deg" : @"Rad", nil);
|
|
||||||
radiansDegreesButton.font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
|
|
||||||
radiansDegreesButton.target = self;
|
|
||||||
radiansDegreesButton.action = @selector(switchRadiansDegrees:);
|
|
||||||
_radiansDegreesButton = radiansDegreesButton;
|
|
||||||
}
|
|
||||||
return _radiansDegreesButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSButton *)functionsButton
|
- (NSButton *)functionsButton
|
||||||
{
|
{
|
||||||
if (!_functionsButton) {
|
if (!_functionsButton) {
|
||||||
@@ -488,7 +506,7 @@
|
|||||||
NSButton *button = [[NSButton alloc] initWithFrame:NSZeroRect];
|
NSButton *button = [[NSButton alloc] initWithFrame:NSZeroRect];
|
||||||
button.translatesAutoresizingMaskIntoConstraints = NO;
|
button.translatesAutoresizingMaskIntoConstraints = NO;
|
||||||
button.target = self;
|
button.target = self;
|
||||||
button.action = @selector(showFunctions:);
|
button.action = @selector(toggleFunctionsPopover:);
|
||||||
button.buttonType = NSMomentaryChangeButton;
|
button.buttonType = NSMomentaryChangeButton;
|
||||||
button.bezelStyle = NSShadowlessSquareBezelStyle;
|
button.bezelStyle = NSShadowlessSquareBezelStyle;
|
||||||
button.bordered = NO;
|
button.bordered = NO;
|
||||||
@@ -546,98 +564,30 @@
|
|||||||
self.selection = MPMakeRangePath(pathToExpression, errorRange.length);
|
self.selection = MPMakeRangePath(pathToExpression, errorRange.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Actions
|
#pragma mark - Mouse Event Handling
|
||||||
- (void)switchRadiansDegrees:(id)sender
|
- (void)mouseDown:(NSEvent *)theEvent
|
||||||
{
|
{
|
||||||
[MPMathRules sharedRules].isUsingDegrees = ![MPMathRules sharedRules].isUsingDegrees;
|
NSPoint pointInView = [self convertPoint:theEvent.locationInWindow
|
||||||
self.radiansDegreesButton.title = NSLocalizedString([MPMathRules sharedRules].isUsingDegrees ? @"Deg" : @"Rad", nil);
|
fromView:nil];
|
||||||
|
NSPoint expressionOrigin = self.expressionOrigin;
|
||||||
|
pointInView.x -= expressionOrigin.x;
|
||||||
|
pointInView.y -= expressionOrigin.y;
|
||||||
|
NSIndexPath *selectionPath = [self.expressionStorage.rootLayout indexPathForMousePoint:pointInView];
|
||||||
|
self.mouseAnchor = selectionPath;
|
||||||
|
self.selection = MPMakeRangePath(selectionPath, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showFunctions:(id)sender
|
- (void)mouseDragged:(NSEvent *)theEvent
|
||||||
{
|
{
|
||||||
if (self.functionsPopover == nil || self.functionsViewController == nil) {
|
NSPoint pointInView = [self convertPoint:theEvent.locationInWindow
|
||||||
self.functionsViewController = [[MPFunctionsViewController alloc] init];
|
fromView:nil];
|
||||||
self.functionsViewController.target = self;
|
NSPoint expressionOrigin = self.expressionOrigin;
|
||||||
self.functionsViewController.action = @selector(insertFunction:);
|
pointInView.x -= expressionOrigin.x;
|
||||||
self.functionsPopover = [[NSPopover alloc] init];
|
pointInView.y -= expressionOrigin.y;
|
||||||
self.functionsPopover.contentViewController = self.functionsViewController;
|
NSIndexPath *mouseSelectionPath = [self.expressionStorage.rootLayout indexPathForMousePoint:pointInView];
|
||||||
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.selection = [self rangePathEnclosingAnchorPath:self.mouseAnchor
|
||||||
{
|
newSelectionPath:mouseSelectionPath];
|
||||||
[self.functionsPopover close];
|
|
||||||
[self.expressionStorage replaceItemsInRangePath:self.selection
|
|
||||||
referenceFrame:MPSymbolReferenceFrame
|
|
||||||
withElements:@[function]];
|
|
||||||
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
|
|
||||||
NSUInteger functionElementIndex = [targetExpression convertIndex:self.selection.location.lastIndex
|
|
||||||
fromReferenceFrame:MPSymbolReferenceFrame
|
|
||||||
toReferenceFrame:MPElementReferenceFrame];
|
|
||||||
NSIndexPath *functionPath = [self.selection.location indexPathByReplacingLastIndexWithIndex:functionElementIndex];
|
|
||||||
MPFunctionLayout *functionLayout = (MPFunctionLayout *)[self.expressionStorage.rootLayout childLayoutAtIndexPath:functionPath];
|
|
||||||
self.selection = MPMakeRangePath([[functionPath indexPathByAddingIndex:functionLayout.indexOfLeadingChild] indexPathByAddingIndex:0], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark NSView Stuff
|
|
||||||
- (BOOL)acceptsFirstResponder
|
|
||||||
{
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)canBecomeKeyView
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isOpaque
|
|
||||||
{
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setFrame:(NSRect)frameRect
|
|
||||||
{
|
|
||||||
[self setNeedsLayout:YES];
|
|
||||||
[super setFrame:frameRect];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSSize)intrinsicContentSize
|
|
||||||
{
|
|
||||||
NSSize size = self.expressionStorage.rootLayout.bounds.size;
|
|
||||||
size.width += 100;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)resetCursorRects
|
|
||||||
{
|
|
||||||
[self addCursorRect:self.bounds
|
|
||||||
cursor:[NSCursor IBeamCursor]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Key Event Handling
|
#pragma mark Key Event Handling
|
||||||
@@ -679,6 +629,57 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Actions
|
||||||
|
- (void)switchToDegrees:(id)sender
|
||||||
|
{
|
||||||
|
[MPMathRules sharedRules].isUsingDegrees = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)switchToRadians:(id)sender
|
||||||
|
{
|
||||||
|
[MPMathRules sharedRules].isUsingDegrees = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)switchRadiansDegrees:(id)sender
|
||||||
|
{
|
||||||
|
[MPMathRules sharedRules].isUsingDegrees = ![MPMathRules sharedRules].isUsingDegrees;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)toggleFunctionsPopover:(id)sender
|
||||||
|
{
|
||||||
|
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 replaceItemsInRangePath:self.selection
|
||||||
|
referenceFrame:MPSymbolReferenceFrame
|
||||||
|
withElements:@[function]];
|
||||||
|
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
|
||||||
|
NSUInteger functionElementIndex = [targetExpression convertIndex:self.selection.location.lastIndex
|
||||||
|
fromReferenceFrame:MPSymbolReferenceFrame
|
||||||
|
toReferenceFrame:MPElementReferenceFrame];
|
||||||
|
NSIndexPath *functionPath = [self.selection.location indexPathByReplacingLastIndexWithIndex:functionElementIndex];
|
||||||
|
MPFunctionLayout *functionLayout = (MPFunctionLayout *)[self.expressionStorage.rootLayout childLayoutAtIndexPath:functionPath];
|
||||||
|
self.selection = MPMakeRangePath([[functionPath indexPathByAddingIndex:functionLayout.indexOfLeadingChild] indexPathByAddingIndex:0], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Editing Actions
|
||||||
|
|
||||||
- (void)insertParenthesisFunction:(id)sender
|
- (void)insertParenthesisFunction:(id)sender
|
||||||
{
|
{
|
||||||
MPExpression *selectedElementsExpression = [self.expressionStorage subexpressionWithRangePath:self.selection
|
MPExpression *selectedElementsExpression = [self.expressionStorage subexpressionWithRangePath:self.selection
|
||||||
@@ -800,6 +801,68 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)deleteBackward:(id)sender
|
||||||
|
{
|
||||||
|
if (self.selection.length > 0) {
|
||||||
|
[self.expressionStorage replaceItemsInRangePath:self.selection
|
||||||
|
referenceFrame:MPSymbolReferenceFrame
|
||||||
|
withElements:@[]];
|
||||||
|
self.selection = MPMakeRangePath(self.selection.location, 0);
|
||||||
|
} else if (self.selection.location.lastIndex > 0) {
|
||||||
|
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
|
||||||
|
id<MPExpressionElement> elementToDelete = [targetExpression elementAtIndex:[targetExpression convertIndex:self.selection.location.lastIndex-1
|
||||||
|
fromReferenceFrame:MPSymbolReferenceFrame
|
||||||
|
toReferenceFrame:MPElementReferenceFrame]];
|
||||||
|
if ([elementToDelete isFunction]) {
|
||||||
|
self.selection = MPMakeRangePath(self.selection.location.indexPathByDecrementingLastIndex, 1);
|
||||||
|
} else {
|
||||||
|
[targetExpression replaceItemsInRange:NSMakeRange(self.selection.location.lastIndex-1, 1)
|
||||||
|
referenceFrame:MPSymbolReferenceFrame
|
||||||
|
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]) {
|
||||||
|
MPExpression *expression = [function childAtIndex:index];
|
||||||
|
[remainder addObjectsFromArray:[expression allItemsInReferenceFrame:MPElementReferenceFrame]];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSIndexPath *newTargetExpressionPath = [functionPath indexPathByRemovingLastIndex];
|
||||||
|
MPExpression *newTargetExpression = [self.expressionStorage elementAtIndexPath:newTargetExpressionPath];
|
||||||
|
NSUInteger newSelectionElementIndex = [newTargetExpression convertIndex:functionPath.lastIndex
|
||||||
|
fromReferenceFrame:MPElementReferenceFrame
|
||||||
|
toReferenceFrame:MPSymbolReferenceFrame];
|
||||||
|
NSIndexPath *newSelectionLocation = [functionPath indexPathByReplacingLastIndexWithIndex:newSelectionElementIndex];
|
||||||
|
|
||||||
|
[self.expressionStorage replaceItemsInRangePath:MPMakeRangePath(newSelectionLocation, 1)
|
||||||
|
referenceFrame:MPSymbolReferenceFrame
|
||||||
|
withElements:remainder];
|
||||||
|
self.selection = MPMakeRangePath(newSelectionLocation, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)delete:(id)sender
|
||||||
|
{
|
||||||
|
[self.expressionStorage replaceItemsInRangePath:self.selection
|
||||||
|
referenceFrame:MPSymbolReferenceFrame
|
||||||
|
withElements:@[]];
|
||||||
|
self.selection = MPMakeRangePath(self.selection.location, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Selection Actions
|
||||||
|
|
||||||
- (void)moveRight:(id)sender
|
- (void)moveRight:(id)sender
|
||||||
{
|
{
|
||||||
if (self.selection.length > 0) {
|
if (self.selection.length > 0) {
|
||||||
@@ -966,84 +1029,6 @@
|
|||||||
self.selection = MPMakeRangePath(location, self.expressionStorage.countSymbols);
|
self.selection = MPMakeRangePath(location, self.expressionStorage.countSymbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)deleteBackward:(id)sender
|
|
||||||
{
|
|
||||||
if (self.selection.length > 0) {
|
|
||||||
[self.expressionStorage replaceItemsInRangePath:self.selection
|
|
||||||
referenceFrame:MPSymbolReferenceFrame
|
|
||||||
withElements:@[]];
|
|
||||||
self.selection = MPMakeRangePath(self.selection.location, 0);
|
|
||||||
} else if (self.selection.location.lastIndex > 0) {
|
|
||||||
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
|
|
||||||
id<MPExpressionElement> elementToDelete = [targetExpression elementAtIndex:[targetExpression convertIndex:self.selection.location.lastIndex-1
|
|
||||||
fromReferenceFrame:MPSymbolReferenceFrame
|
|
||||||
toReferenceFrame:MPElementReferenceFrame]];
|
|
||||||
if ([elementToDelete isFunction]) {
|
|
||||||
self.selection = MPMakeRangePath(self.selection.location.indexPathByDecrementingLastIndex, 1);
|
|
||||||
} else {
|
|
||||||
[targetExpression replaceItemsInRange:NSMakeRange(self.selection.location.lastIndex-1, 1)
|
|
||||||
referenceFrame:MPSymbolReferenceFrame
|
|
||||||
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]) {
|
|
||||||
MPExpression *expression = [function childAtIndex:index];
|
|
||||||
[remainder addObjectsFromArray:[expression allItemsInReferenceFrame:MPElementReferenceFrame]];
|
|
||||||
}
|
|
||||||
|
|
||||||
NSIndexPath *newTargetExpressionPath = [functionPath indexPathByRemovingLastIndex];
|
|
||||||
MPExpression *newTargetExpression = [self.expressionStorage elementAtIndexPath:newTargetExpressionPath];
|
|
||||||
NSUInteger newSelectionElementIndex = [newTargetExpression convertIndex:functionPath.lastIndex
|
|
||||||
fromReferenceFrame:MPElementReferenceFrame
|
|
||||||
toReferenceFrame:MPSymbolReferenceFrame];
|
|
||||||
NSIndexPath *newSelectionLocation = [functionPath indexPathByReplacingLastIndexWithIndex:newSelectionElementIndex];
|
|
||||||
|
|
||||||
[self.expressionStorage replaceItemsInRangePath:MPMakeRangePath(newSelectionLocation, 1)
|
|
||||||
referenceFrame:MPSymbolReferenceFrame
|
|
||||||
withElements:remainder];
|
|
||||||
self.selection = MPMakeRangePath(newSelectionLocation, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Mouse Event Handling
|
|
||||||
- (void)mouseDown:(NSEvent *)theEvent
|
|
||||||
{
|
|
||||||
NSPoint pointInView = [self convertPoint:theEvent.locationInWindow
|
|
||||||
fromView:nil];
|
|
||||||
NSPoint expressionOrigin = self.expressionOrigin;
|
|
||||||
pointInView.x -= expressionOrigin.x;
|
|
||||||
pointInView.y -= expressionOrigin.y;
|
|
||||||
NSIndexPath *selectionPath = [self.expressionStorage.rootLayout indexPathForMousePoint:pointInView];
|
|
||||||
self.mouseAnchor = selectionPath;
|
|
||||||
self.selection = MPMakeRangePath(selectionPath, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)mouseDragged:(NSEvent *)theEvent
|
|
||||||
{
|
|
||||||
NSPoint pointInView = [self convertPoint:theEvent.locationInWindow
|
|
||||||
fromView:nil];
|
|
||||||
NSPoint expressionOrigin = self.expressionOrigin;
|
|
||||||
pointInView.x -= expressionOrigin.x;
|
|
||||||
pointInView.y -= expressionOrigin.y;
|
|
||||||
NSIndexPath *mouseSelectionPath = [self.expressionStorage.rootLayout indexPathForMousePoint:pointInView];
|
|
||||||
|
|
||||||
self.selection = [self rangePathEnclosingAnchorPath:self.mouseAnchor
|
|
||||||
newSelectionPath:mouseSelectionPath];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Drawing Methods
|
#pragma mark Drawing Methods
|
||||||
- (void)drawRect:(NSRect)dirtyRect
|
- (void)drawRect:(NSRect)dirtyRect
|
||||||
{
|
{
|
||||||
@@ -1078,4 +1063,26 @@
|
|||||||
[self.expressionStorage.rootLayout drawAtPoint:expressionOrigin];
|
[self.expressionStorage.rootLayout drawAtPoint:expressionOrigin];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - User Interface Validations
|
||||||
|
|
||||||
|
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)anItem
|
||||||
|
{
|
||||||
|
BOOL degrees = [MPMathRules sharedRules].isUsingDegrees;
|
||||||
|
if (anItem.action == @selector(switchToRadians:)) {
|
||||||
|
id anObject = anItem;
|
||||||
|
if ([anObject respondsToSelector:@selector(setState:)]) {
|
||||||
|
[anObject setState:degrees?NSOffState:NSOnState];
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
} else if (anItem.action == @selector(switchToDegrees:)) {
|
||||||
|
id anObject = anItem;
|
||||||
|
if ([anObject respondsToSelector:@selector(setState:)]) {
|
||||||
|
[anObject setState:degrees?NSOnState:NSOffState];
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
Reference in New Issue
Block a user