Archived
1

Removed Deg/Rad Button, Replaced with Menu Actions

This commit is contained in:
Kim Wittenburg
2014-12-17 22:05:22 +01:00
parent 7f6ee6e118
commit 5aef06febe

View File

@@ -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; self.selection = [self rangePathEnclosingAnchorPath:self.mouseAnchor
} newSelectionPath:mouseSelectionPath];
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 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