Redesigned Error Display
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6245" systemVersion="14A389" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6250" systemVersion="14B25" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6245"/>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6250"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="MPDocument">
|
||||
@@ -35,22 +36,22 @@
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="4B1-d4-7wd" secondAttribute="bottom" constant="20" symbolic="YES" id="Gnf-6p-lx6"/>
|
||||
<constraint firstAttribute="trailing" secondItem="4B1-d4-7wd" secondAttribute="trailing" constant="20" symbolic="YES" id="paI-1L-J2e"/>
|
||||
<constraint firstAttribute="trailing" secondItem="4B1-d4-7wd" secondAttribute="trailing" constant="20" symbolic="YES" id="Ls8-DM-Zjx"/>
|
||||
<constraint firstAttribute="bottom" secondItem="4B1-d4-7wd" secondAttribute="bottom" constant="20" symbolic="YES" id="i5Y-pJ-a4a"/>
|
||||
</constraints>
|
||||
</customView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="bhV-kp-c0I" secondAttribute="bottom" id="VRz-hN-lFY"/>
|
||||
<constraint firstItem="bhV-kp-c0I" firstAttribute="leading" secondItem="gIp-Ho-8D9" secondAttribute="leading" id="WbH-hd-lvs"/>
|
||||
<constraint firstAttribute="trailing" secondItem="bhV-kp-c0I" secondAttribute="trailing" id="nYd-dS-gsv"/>
|
||||
<constraint firstItem="bhV-kp-c0I" firstAttribute="top" secondItem="gIp-Ho-8D9" secondAttribute="top" id="png-CY-BRy"/>
|
||||
<constraint firstItem="bhV-kp-c0I" firstAttribute="top" secondItem="gIp-Ho-8D9" secondAttribute="top" id="Fxa-FH-JSm"/>
|
||||
<constraint firstAttribute="trailing" secondItem="bhV-kp-c0I" secondAttribute="trailing" id="OmV-Md-fan"/>
|
||||
<constraint firstAttribute="bottom" secondItem="bhV-kp-c0I" secondAttribute="bottom" id="Orq-IZ-y4Z"/>
|
||||
<constraint firstItem="bhV-kp-c0I" firstAttribute="leading" secondItem="gIp-Ho-8D9" secondAttribute="leading" id="ZBu-f7-Tp8"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="-2" id="0bl-1N-x8E"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-147" y="119.5"/>
|
||||
<point key="canvasLocation" x="-32" y="380.5"/>
|
||||
</window>
|
||||
<collectionViewItem id="J9S-PW-LCL">
|
||||
<connections>
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#import "MPDocument.h"
|
||||
|
||||
#import "MPParsedExpression.h"
|
||||
|
||||
@implementation MPDocument
|
||||
|
||||
- (id)init
|
||||
@@ -60,13 +62,15 @@
|
||||
|
||||
#pragma mark Actions
|
||||
- (IBAction)evaluateExpression:(id)sender {
|
||||
NSError *error;
|
||||
NSDecimalNumber *result = [self.expressionView.expressionStorage evaluateWithError:&error];
|
||||
if (error) {
|
||||
self.expressionView.errorMessageTextField.stringValue = error.localizedDescription;
|
||||
} else {
|
||||
self.expressionView.errorMessageTextField.stringValue = @"";
|
||||
NSArray *errors;
|
||||
MPParsedExpression *parsedExpression = [self.expressionView.expressionStorage parse:&errors];
|
||||
NSError *mathError;
|
||||
NSDecimalNumber *result;
|
||||
if (parsedExpression) {
|
||||
result = [parsedExpression evaluate:&mathError];
|
||||
}
|
||||
self.expressionView.syntaxErrors = errors;
|
||||
self.expressionView.mathError = mathError;
|
||||
self.resultLabel.stringValue = result != nil ? [result descriptionWithLocale:[NSLocale currentLocale]] : @"";
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
// TODO: Undo/Redo + Delegate
|
||||
// TODO: Undo/Redo + Delegate (evaluateExpressionView:evaluate...)
|
||||
|
||||
@class MPExpressionView, MPExpressionStorage, MPExpressionLayout, MPRangePath;
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
|
||||
@property (nonatomic, strong) MPRangePath *selection;
|
||||
|
||||
@property (nonatomic, strong) NSTextField *errorMessageTextField;
|
||||
@property (nonatomic, strong) NSError *mathError;
|
||||
@property (nonatomic, strong) NSArray *syntaxErrors;
|
||||
|
||||
@property (nonatomic, weak) id target;
|
||||
@property (nonatomic) SEL action;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#import "MPExpression.h"
|
||||
#import "MPExpressionElement.h"
|
||||
#import "MPParsedExpression.h"
|
||||
|
||||
#import "MPPowerFunction.h"
|
||||
#import "MPParenthesisFunction.h"
|
||||
@@ -20,6 +21,7 @@
|
||||
|
||||
#import "MPExpressionStorage.h"
|
||||
#import "MPExpressionLayout.h"
|
||||
#import "MPFunctionLayout.h"
|
||||
|
||||
#import "MPFunctionsViewController.h"
|
||||
|
||||
@@ -33,6 +35,9 @@
|
||||
@property (nonatomic, strong) NSPopover *functionsPopover;
|
||||
@property (nonatomic, strong) MPFunctionsViewController *functionsViewController;
|
||||
|
||||
@property (nonatomic, strong) NSPopUpButton *syntaxErrorsPopUpButton;
|
||||
@property (nonatomic, strong) NSTextField *mathErrorTextField;
|
||||
|
||||
@property (nonatomic, strong) NSTimer *caretTimer;
|
||||
@property (nonatomic) NSTimeInterval caretBlinkRate;
|
||||
@property (nonatomic) BOOL caretVisible;
|
||||
@@ -336,7 +341,7 @@
|
||||
_expressionStorage = expressionStorage;
|
||||
|
||||
[self initializeButtons];
|
||||
[self initializeErrorMessageTextField];
|
||||
[self initializeErrorsViews];
|
||||
|
||||
self.selection = [[MPRangePath alloc] initWithRange:NSMakeRange(0, 0)];
|
||||
self.caretBlinkRate = 1.0;
|
||||
@@ -374,16 +379,27 @@
|
||||
constant:0]];
|
||||
}
|
||||
|
||||
- (void)initializeErrorMessageTextField
|
||||
- (void)initializeErrorsViews
|
||||
{
|
||||
NSTextField *errorLabel = self.errorMessageTextField;
|
||||
[self addSubview:errorLabel];
|
||||
NSDictionary *variableBindings = NSDictionaryOfVariableBindings(errorLabel);
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[errorLabel]"
|
||||
|
||||
NSPopUpButton *syntaxErrors = self.syntaxErrorsPopUpButton;
|
||||
NSTextField *mathError = self.mathErrorTextField;
|
||||
[self addSubview:syntaxErrors];
|
||||
[self addSubview:mathError];
|
||||
NSDictionary *variableBindings = NSDictionaryOfVariableBindings(syntaxErrors, mathError);
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[syntaxErrors]"
|
||||
options:0
|
||||
metrics:nil
|
||||
views:variableBindings]];
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[errorLabel]-10-|"
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[syntaxErrors]-10-|"
|
||||
options:0
|
||||
metrics:nil
|
||||
views:variableBindings]];
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[mathError]"
|
||||
options:0
|
||||
metrics:nil
|
||||
views:variableBindings]];
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[mathError]-10-|"
|
||||
options:0
|
||||
metrics:nil
|
||||
views:variableBindings]];
|
||||
@@ -405,6 +421,42 @@
|
||||
self.needsDisplay = YES;
|
||||
}
|
||||
|
||||
- (void)setSyntaxErrors:(NSArray *)syntaxErrors
|
||||
{
|
||||
_syntaxErrors = syntaxErrors;
|
||||
[self.syntaxErrorsPopUpButton removeAllItems];
|
||||
if (syntaxErrors.count == 0) {
|
||||
self.syntaxErrorsPopUpButton.hidden = YES;
|
||||
return;
|
||||
}
|
||||
self.syntaxErrorsPopUpButton.hidden = NO;
|
||||
[self.syntaxErrorsPopUpButton addItemWithTitle:@""];
|
||||
if (syntaxErrors.count == 1) {
|
||||
NSString *title = NSLocalizedString(@"1 Syntax Error", nil);
|
||||
NSDictionary *attributes = @{NSForegroundColorAttributeName: [NSColor redColor],
|
||||
NSFontAttributeName: [NSFont boldSystemFontOfSize:12.0]};
|
||||
NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString:title attributes:attributes];
|
||||
[self.syntaxErrorsPopUpButton itemAtIndex:0].attributedTitle = attributedTitle;
|
||||
} else {
|
||||
NSString *title = [NSString stringWithFormat:NSLocalizedString(@"%ld Syntax Errors", nil), syntaxErrors.count];
|
||||
NSDictionary *attributes = @{NSForegroundColorAttributeName: [NSColor redColor],
|
||||
NSFontAttributeName: [NSFont boldSystemFontOfSize:12.0]};
|
||||
NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString:title attributes:attributes];
|
||||
[self.syntaxErrorsPopUpButton itemAtIndex:0].attributedTitle = attributedTitle;
|
||||
}
|
||||
NSUInteger index = 0;
|
||||
for (NSError *error in syntaxErrors) {
|
||||
[self.syntaxErrorsPopUpButton addItemWithTitle:error.localizedDescription];
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setMathError:(NSError *)mathError
|
||||
{
|
||||
_mathError = mathError;
|
||||
self.mathErrorTextField.stringValue = mathError != nil ? mathError.localizedDescription : @"";
|
||||
}
|
||||
|
||||
- (NSButton *)radiansDegreesButton
|
||||
{
|
||||
if (!_radiansDegreesButton) {
|
||||
@@ -447,19 +499,46 @@
|
||||
return _functionsButton;
|
||||
}
|
||||
|
||||
- (NSTextField *)errorMessageTextField
|
||||
- (NSPopUpButton *)syntaxErrorsPopUpButton
|
||||
{
|
||||
if (!_errorMessageTextField) {
|
||||
NSTextField *label = [[NSTextField alloc] initWithFrame:NSZeroRect];
|
||||
label.textColor = [NSColor redColor];
|
||||
label.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
label.bezeled = NO;
|
||||
label.drawsBackground = NO;
|
||||
label.editable = NO;
|
||||
label.selectable = NO;
|
||||
_errorMessageTextField = label;
|
||||
if (!_syntaxErrorsPopUpButton) {
|
||||
NSPopUpButton *button = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 26)
|
||||
pullsDown:YES];
|
||||
button.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[button.cell setArrowPosition:NSPopUpArrowAtBottom];
|
||||
button.bezelStyle = NSRecessedBezelStyle;
|
||||
button.buttonType = NSPushOnPushOffButton;
|
||||
button.showsBorderOnlyWhileMouseInside = YES;
|
||||
button.font = [NSFont boldSystemFontOfSize:12.0];
|
||||
button.hidden = YES;
|
||||
button.target = self;
|
||||
button.action = @selector(didSelectError:);
|
||||
_syntaxErrorsPopUpButton = button;
|
||||
}
|
||||
return _errorMessageTextField;
|
||||
return _syntaxErrorsPopUpButton;
|
||||
}
|
||||
|
||||
- (NSTextField *)mathErrorTextField
|
||||
{
|
||||
if (!_mathErrorTextField) {
|
||||
NSTextField *textField = [[NSTextField alloc] init];
|
||||
textField.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
textField.bordered = NO;
|
||||
textField.selectable = NO;
|
||||
textField.editable = NO;
|
||||
textField.textColor = [NSColor redColor];
|
||||
textField.font = [NSFont boldSystemFontOfSize:12.0];
|
||||
_mathErrorTextField = textField;
|
||||
}
|
||||
return _mathErrorTextField;
|
||||
}
|
||||
|
||||
- (void)didSelectError:(NSPopUpButton *)sender
|
||||
{
|
||||
NSError *error = self.syntaxErrors[sender.indexOfSelectedItem-1];
|
||||
NSIndexPath *pathToExpression = error.userInfo[MPPathToExpressionKey];
|
||||
pathToExpression = [pathToExpression indexPathByAddingIndex:[error.userInfo[MPErrorIndexKey] integerValue]];
|
||||
self.selection = MPMakeRangePath(pathToExpression, 0);
|
||||
}
|
||||
|
||||
#pragma mark Actions
|
||||
|
||||
Reference in New Issue
Block a user