|
|
1.1 root 1: /*
2: * SimpleCalc -- Randy Nelson
3: * A general class that directly supports a calculator interface
4: * Created 8-8-90
5: *
6: * You may freely copy, distribute and reuse the code in this example.
7: * NeXT disclaims any warranty of any kind, expressed or implied, as to
8: * its fitness for any particular use.
9: */
10:
11: #import "SimpleCalc.h"
12: #import <appkit/Application.h>
13: #import <objc/NXStringTable.h>
14: #import <appkit/Panel.h>
15: #import <appkit/Text.h>
16: #import <appkit/Button.h>
17: #import <appkit/publicWraps.h>
18: #import <stdio.h>
19: #import <strings.h>
20:
21: #define DECIMALPOINT 10
22: #define DIVIDE 20
23: #define MULTIPLY 21
24: #define SUBTRACT 22
25: #define ADD 23
26: #define CLEAR 31
27: #define CLEARALL 30
28:
29: @implementation SimpleCalc
30: - init
31: {
32: [super init];
33: [self doInit];
34: return self;
35: }
36:
37: - doInit
38: {
39: accumulator = 0;
40: operator = 0;
41: numberHasADecimal = NO;
42: startingSecondNumber = NO;
43: treatingOperationKeyLikeEqualKey = NO;
44: noFirstNumber = YES;
45: return self;
46: }
47:
48: - numberKeys:sender
49: {
50: char aDigit[2];
51: int digit = [sender selectedTag];
52:
53: noFirstNumber = NO;
54:
55: /* clear the display in order to begin the second number */
56: if(startingSecondNumber == YES){
57: [display setStringValue:""];
58: startingSecondNumber = NO;
59: }
60: if(digit == DECIMALPOINT){
61: [self decimal];
62: return self;
63: }
64: sprintf(aDigit, "%d", digit);
65: [self appendToDisplay:(const char *)aDigit];
66: return self;
67: }
68:
69: - decimal
70: {
71: if(numberHasADecimal == YES){
72: NXBeep();
73: return self;
74: }
75: /* internationalizable strings */
76: [self appendToDisplay:[stringSet valueForStringKey:"decimalPointString"]];
77: numberHasADecimal = YES;
78: return self;
79: }
80:
81: - operationKeys:sender
82: {
83: //do nothing if noFirstNumber
84: if(noFirstNumber == YES){
85: NXBeep();
86: return self;
87: }
88:
89: /* if there's an operation and a first and second number
90: * act like the equal key was pressed
91: */
92: if((treatingOperationKeyLikeEqualKey == YES) &&
93: (startingSecondNumber == NO)){
94: [self equalsKey:self];
95: }
96: operator = [sender selectedTag];
97: switch(operator){
98: case DIVIDE: case MULTIPLY: case SUBTRACT: case ADD:{
99: accumulator = [display doubleValue];
100: numberHasADecimal = NO;
101: startingSecondNumber = YES;
102: treatingOperationKeyLikeEqualKey = YES;
103: break;
104: }
105: default:{
106: return self;
107: }
108: }
109: return self;
110: }
111:
112: - equalsKey:sender
113: {
114: /* do nothing if noFirstNumber */
115: if(noFirstNumber == YES){
116: NXBeep();
117: return self;
118: }
119: switch(operator){
120: case DIVIDE:{
121: if([display doubleValue] == 0){
122: //can't divide by zero
123: NXBeep();
124: return self;
125: }
126: [display setDoubleValue:(accumulator / [display doubleValue])];
127: break;
128: }
129: case MULTIPLY:{
130: [display setDoubleValue:(accumulator * [display doubleValue])];
131: break;
132: }
133: case SUBTRACT:{
134: [display setDoubleValue:(accumulator - [display doubleValue])];
135: break;
136: }
137: case ADD:{
138: [display setDoubleValue:(accumulator + [display doubleValue])];
139: break;
140: }
141: default:{
142: return self;
143: }
144: }
145: /* just lke doInit
146: * but startingSecondNumber gets YES
147: * and noFirstNumber continues to be NO (there is a first number)
148: */
149: operator = 0;
150: accumulator = 0;
151: numberHasADecimal = NO;
152: startingSecondNumber = YES;
153: treatingOperationKeyLikeEqualKey = NO;
154: return self;
155: }
156:
157: - clearKeys:sender
158: {
159: switch([sender selectedTag]){
160: case CLEAR:{
161: [display setStringValue:[stringSet
162: valueForStringKey:"zeroString"]];
163: numberHasADecimal = NO;
164: startingSecondNumber = YES;
165: break;
166: }
167: case CLEARALL:{
168: [display setStringValue:[stringSet
169: valueForStringKey:"zeroString"]];
170: [self doInit];
171: break;
172: }
173: default:{
174: break;
175: }
176: }
177: return self;
178: }
179:
180: - appendToDisplay:(const char *)theDigit
181: {
182: char *copyOfDisplay = NXCopyStringBuffer([display stringValue]);
183:
184: /* if the display's current value is zero */
185: if([display doubleValue] == 0){
186:
187: /* and the zero doesn't have a decimal point */
188: if(numberHasADecimal == NO){
189:
190: /* replace the display with the digit passed */
191: [display setStringValue:theDigit];
192: return self;
193: }
194: }
195: /* otherwise append the digit passed
196: * to the digits already in the display
197: */
198: [display setStringValue:strcat(copyOfDisplay, theDigit)];
199:
200: return self;
201: }
202:
203: - numberDirectFromDisplay:sender
204: {
205: noFirstNumber = NO;
206: startingSecondNumber = YES;
207: return self;
208: }
209:
210: - appDidInit:sender
211: {
212: /* enter key can't be set as key equivalent from IB */
213: [enterKey setKeyEquivalent:3];
214: [[display window] makeKeyAndOrderFront:self];
215: return self;
216: }
217:
218: - windowWillClose:window
219: {
220: return [NXApp terminate:self];
221: }
222:
223: - infoPanel:sender
224: {
225: if(infoPanel == nil){
226: [NXApp loadNibSection:"Info.nib" owner:self];
227: }
228: [infoPanel orderFront:sender];
229: return self;
230: }
231:
232: - helpPanel:sender
233: {
234: if(helpPanel == nil){
235: [NXApp loadNibSection:"Help.nib" owner:self];
236: }
237: [helpPanel orderFront:sender];
238: return self;
239:
240: }
241: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.