1#include <pthread.h>
2#include "calculator.h"
3#include "variables.h"
4#include "conversion.h"
5#include "ErrorController.h"
6#include "historyManager.h"
7#include "WcalcController.h"
8#include "string_manip.h"
9#include "files.h"
10#include "MyTextField.h"
11#include "simpleCalc.h"
12#include "list.h"
13#include "number.h"
14
15#define KEYPAD_HEIGHT 165
16#define MIN_WINDOW_WIDTH 171
17#define MIN_WINDOW_HEIGHT_TOGGLED 112
18#define MIN_WINDOW_HEIGHT_UNTOGGLED 277
19#define FIELD_WIDTH_DIFFERENCE 22
20#define MAX_WINDOW_SIZE 10000
21
22static char update_history = 0;
23NSButton *e;
24NSTextField *ef;
25static NSString *curFile = NULL;
26static pthread_mutex_t displayLock;
27
28@implementation WcalcController
29
30- (IBAction)toggleSize:(id)sender
31{
32    static BOOL shrinking = TRUE;
33    NSRect mainwindow = [mainWindow frame];
34    NSRect expr = [ExpressionField frame];
35    NSRect prec = [PrecisionSlider frame];
36    NSRect ans = [AnswerField frame];
37    NSSize w;
38    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
39
40    if (shrinking) {
41	// if removing the keypad, change the window height
42	mainwindow.size.height -= KEYPAD_HEIGHT;
43	mainwindow.origin.y += KEYPAD_HEIGHT;
44	// this is set in case the calc starts up toggled (under other
45	// conditions it is not strictly necessary, because the ExpressionField
46	// has achieved the correct size automatically
47	expr.size.height = mainwindow.size.height
48	    - ans.size.height
49	    - prec.size.height
50	    - 57 /* the size of the rest of the window, including title bar */;
51	[sizeToggleMenu setTitle:@"Show Keypad"];
52    } else {
53	// if adding the keypad, change the window height
54	mainwindow.size.height += KEYPAD_HEIGHT;
55	mainwindow.origin.y -= KEYPAD_HEIGHT;
56	mainwindow.size.width = MIN_WINDOW_WIDTH;
57	[sizeToggleMenu setTitle:@"Hide Keypad"];
58    }
59
60    expr.size.width = prec.size.width = mainwindow.size.width - FIELD_WIDTH_DIFFERENCE;
61
62    if (shrinking) {
63	[keypad removeFromSuperview];
64	expr.origin.y -= KEYPAD_HEIGHT;
65	prec.origin.y -= KEYPAD_HEIGHT;
66    } else {
67	expr.origin.y += KEYPAD_HEIGHT;
68	prec.origin.y += KEYPAD_HEIGHT;
69    }
70
71    [ExpressionField removeFromSuperview];
72    [PrecisionSlider removeFromSuperview];
73
74    if (sender != 0) {
75	[mainWindow setFrame:mainwindow display:TRUE animate:TRUE];
76    } else {
77	[mainWindow setFrame:mainwindow display:FALSE animate:FALSE];
78    }
79
80    if (! shrinking) {
81	[superview addSubview:keypad];
82	w.width = MIN_WINDOW_WIDTH;
83	w.height = MIN_WINDOW_HEIGHT_UNTOGGLED + (ans.size.height - 21);
84	[mainWindow setMinSize:w];
85	w.width = MIN_WINDOW_WIDTH;
86	w.height = MAX_WINDOW_SIZE;
87	[mainWindow setMaxSize:w];
88	[prefs setObject:@"NO" forKey:@"toggled"];
89    } else {
90	w.width = MIN_WINDOW_WIDTH;
91	w.height = MIN_WINDOW_HEIGHT_TOGGLED + (ans.size.height - 21);
92	[mainWindow setMinSize:w];
93	w.width = MAX_WINDOW_SIZE;
94	w.height = MAX_WINDOW_SIZE;
95	[mainWindow setMaxSize:w];
96	[prefs setObject:@"YES" forKey:@"toggled"];
97    }
98
99    [ExpressionField setFrame:expr];
100    [PrecisionSlider setFrame:prec];
101
102    [superview addSubview:ExpressionField];
103    [superview addSubview:PrecisionSlider];
104
105    [ExpressionField selectText:sender];
106
107    shrinking = ! shrinking;
108}
109
110- (IBAction)clear:(id)sender
111{
112    if ([[ExpressionField stringValue] length]) {
113	[ExpressionField setStringValue:@""];
114	[ExpressionField selectText:self];
115    } else if ([[AnswerField stringValue] length]) {
116	[AnswerField setStringValue:@""];
117	[ExpressionField selectText:self];
118    }
119}
120
121- (IBAction)menuConstant:(id)sender
122{
123    NSString *str = [ExpressionField stringValue];
124    NSString *str2 = @"error!";
125
126    switch ([sender tag]) {
127	case 1: str2 = [NSString stringWithFormat:@"%C", 0x03c0]; break;
128	case 2: str2 = @"e"; break;
129	case 3: str2 = [NSString stringWithFormat:@"%C", 0x03b3]; break;
130	case 4: str2 = @"g"; break;
131	case 5: str2 = @"Cc"; break;
132	case 8: str = @"K"; break;
133
134	case 101: str2 = @"Z0"; break;
135	case 102: str2 = [NSString stringWithFormat:@"%C0", 0x03b5]; break;
136	case 103: str2 = [NSString stringWithFormat:@"%C0", 0x03bc]; break;
137	case 104: str2 = @"G"; break;
138	case 105: str2 = @"h"; break;
139	case 106: str2 = @"c"; break;
140
141	case 201: str2 = [NSString stringWithFormat:@"%CB", 0x03bc]; break;
142	case 202: str2 = [NSString stringWithFormat:@"%CN", 0x03bc]; break;
143	case 203: str2 = @"G0"; break;
144	case 204: str2 = @"ec"; break;
145	case 205: str2 = @"Kj"; break;
146	case 206: str2 = @"Rk"; break;
147	case 207: str2 = [NSString stringWithFormat:@"%C0", 0x03a6]; break;
148
149	case 301: str2 = [NSString stringWithFormat:@"M%C", 0x03b1]; break;
150	case 302: str2 = @"a0"; break;
151	case 303: str2 = @"Md"; break;
152	case 304: str2 = @"Me"; break;
153	case 305: str2 = @"re"; break;
154	case 306: str2 = @"eV"; break;
155	case 307: str2 = @"Gf"; break;
156	case 308: str2 = [NSString stringWithFormat:@"%C", 0x03b1]; break;
157	case 309: str2 = @"Eh"; break;
158	case 310: str2 = @"Mh"; break;
159	case 311: str2 = [NSString stringWithFormat:@"m%C", 0x03bc]; break;
160	case 312: str2 = @"Mn"; break;
161	case 313: str2 = @"Mp"; break;
162	case 314: str2 = [NSString stringWithFormat:@"R%C", 0x221E]; break;
163	case 315: str2 = [NSString stringWithFormat:@"M%C", 0x03c4]; break;
164
165	case 401: str2 = @"u"; break;
166	case 402: str2 = @"Na"; break;
167	case 403: str2 = @"k"; break;
168	case 404: str2 = @"F"; break;
169	case 405: str2 = @"c1"; break;
170	case 406: str2 = @"n0"; break;
171	case 407: str2 = @"R"; break;
172	case 408: str2 = @"Vm"; break;
173	case 409: str2 = @"c2"; break;
174	case 410: str2 = [NSString stringWithFormat:@"%C", 0x03c3]; break;
175	case 411: str2 = @"b"; break;
176
177	case 6: str2 = @"random"; break;
178	case 7: str2 = @"irandom"; break;
179	default: return;
180    }
181    if ([str length]) {
182	NSString *str3 = [NSString stringWithFormat:@"%C",0x00d7];
183	[ExpressionField setStringValue:[str stringByAppendingString:[str3 stringByAppendingString:str2]]];
184    } else {
185	[ExpressionField setStringValue:str2];
186    }
187}
188
189- (IBAction)menuFunction:(id)sender
190{
191    NSString *str = [[ExpressionField stringValue] stringByAppendingString:@")"];
192    NSString *str2;
193
194    if ([str length] == 1) str = @"";
195
196    switch ([sender tag]) {
197	case 1: str2 = @"sin("; break;
198	case 2: str2 = @"cos("; break;
199	case 3: str2 = @"tan("; break;
200	case 4: str2 = @"asin("; break;
201	case 5: str2 = @"acos("; break;
202	case 6: str2 = @"atan("; break;
203	case 7: str2 = @"sinh("; break;
204	case 8: str2 = @"cosh("; break;
205	case 9: str2 = @"tanh("; break;
206	case 10: str2 = @"asinh("; break;
207	case 11: str2 = @"acosh("; break;
208	case 12: str2 = @"atanh("; break;
209	case 13: str2 = @"log("; break;
210	case 14: str2 = @"ln("; break;
211	case 15: str2 = @"round("; break;
212	case 16: str2 = @"abs("; break;
213	case 17: str2 = @"sqrt("; break;
214	case 18: str2 = @"floor("; break;
215	case 19: str2 = @"ceil("; break;
216	case 20: str2 = @"cbrt("; break;
217	case 21: str2 = @"logtwo("; break;
218	case 22: str2 = @"cot("; break;
219	case 23: str2 = @"acot("; break;
220	case 24: str2 = @"coth("; break;
221	case 25: str2 = @"acoth("; break;
222	case 26: str2 = @"rand("; break;
223	case 27: str2 = @"irand("; break;
224	case 28: str2 = @"Gamma("; break;
225	case 29: str2 = @"lnGamma("; break;
226	case 30: str2 = @"zeta("; break;
227	case 31: str2 = @"sec("; break;
228	case 32: str2 = @"csc("; break;
229	case 33: str2 = @"asec("; break;
230	case 34: str2 = @"acsc("; break;
231	case 35: str2 = @"sech("; break;
232	case 36: str2 = @"csch("; break;
233	case 37: str2 = @"asech("; break;
234	case 38: str2 = @"acsch("; break;
235	case 39: str2 = @"eint("; break;
236	case 40: str2 = @"sinc("; break;
237	case 41: str2 = @"exp("; break;
238	case 42: str2 = @"fact("; break;
239	case 43: str2 = @"comp("; break;
240	default: return;
241    }
242    [ExpressionField setStringValue:[str2 stringByAppendingString:str]];
243}
244
245- (void)awakeFromNib
246{
247    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
248    NSRect w;
249    NSSize bounds;
250    int prefsVersion;
251
252    Dprintf("awakeFromNib\n");
253    prefsVersion = [prefs integerForKey:@"initialized"];
254    Dprintf("prefsVersion: %i\n", prefsVersion);
255    if (prefsVersion < 1) {
256	Dprintf("Upgrading prefs to v1\n");
257	[prefs setObject:@"-1" forKey:@"precision"];
258	[prefs setObject:@"NO" forKey:@"historyDuplicatesAllowed"];
259	[prefs setObject:@"NO" forKey:@"flagUndefinedVariables"];
260	[prefs setObject:@"YES" forKey:@"useRadians"];
261	[prefs setObject:@"0" forKey:@"outputFormat"];
262	[prefs setObject:@"YES" forKey:@"printPrefixes"];
263	[prefs setObject:@"NO" forKey:@"updateHistory"];
264	[prefs setObject:@"YES" forKey:@"strictSyntax"];
265	[prefs setObject:@"0" forKey:@"roundingIndication"];
266	[prefs setObject:@"NO" forKey:@"historyShowing"];
267	[prefs setObject:@"YES" forKey:@"rememberErrors"];
268	[prefs setObject:@"NO" forKey:@"baseShowing"];
269	[prefs setObject:@"YES" forKey:@"precisionGuard"];
270	[prefs setObject:@"NO" forKey:@"historyLimit"];
271	[prefs setObject:@"1000" forKey:@"historyLimitLength"];
272	[prefs setObject:@"NO" forKey:@"printInts"];
273	[prefs setObject:@"NO" forKey:@"simpleCalc"];
274	[prefs setObject:@"NO" forKey:@"printDelimiters"];
275    }
276    if (prefsVersion < 2) {
277	Dprintf("Upgrading prefs to v2\n");
278	[prefs setObject:@"YES" forKey:@"livePrecision"];
279	[prefs setObject:@"1024" forKey:@"internalPrecision"];
280	[prefs setObject:@"YES" forKey:@"cModStyle"];
281    }
282    if (prefsVersion < 3) {
283	Dprintf("Upgrading prefs to v3\n");
284	[prefs setObject:@"3" forKey:@"initialized"];
285	[prefs setObject:@"147" forKey:@"maxSliderPrecision"];
286    }
287    if (prefsVersion < 4) {
288	Dprintf("Upgrading prefs to v4\n");
289	[prefs setObject:@"4" forKey:@"initialized"];
290	[prefs setObject:@"1" forKey:@"engineeringNotation"];
291    }
292    if (prefsVersion < 5) {
293	Dprintf("Upgrading prefs to v5\n");
294	[prefs setObject:@"5" forKey:@"initialized"];
295	[prefs setObject:@"" forKey:@"alternateInputDecimalSeparator"];
296	[prefs setObject:@"" forKey:@"alternateInputThousandsSeparator"];
297    }
298    conf.precision = [prefs integerForKey:@"precision"];
299    switch([prefs integerForKey:@"engineeringNotation"]) {
300		case 1: conf.engineering = automatic; break;
301		case 2: conf.engineering = never; break;
302		case 3: conf.engineering = always; break;
303	}
304    conf.picky_variables = [prefs boolForKey:@"flagUndefinedVariables"];
305    conf.use_radians = [prefs boolForKey:@"useRadians"];
306    conf.output_format = [prefs integerForKey:@"outputFormat"];
307    conf.print_prefixes = [prefs boolForKey:@"printPrefixes"];
308    /*	conf.strict_syntax = [prefs boolForKey:@"strictSyntax"]; */
309    conf.rounding_indication = [prefs integerForKey:@"roundingIndication"];
310    conf.precision_guard = [prefs boolForKey:@"precisionGuard"];
311    conf.print_ints = [prefs boolForKey:@"printInts"];
312    conf.print_commas = [prefs boolForKey:@"printDelimiters"];
313    conf.simple_calc = [prefs boolForKey:@"simpleCalc"];
314    conf.live_precision = [prefs boolForKey:@"livePrecision"];
315    [PrecisionSlider setMaxValue:[prefs floatForKey:@"maxSliderPrecision"]];
316    /* history preferences */
317    allow_duplicates = [prefs boolForKey:@"historyDuplicatesAllowed"];
318    update_history = [prefs boolForKey:@"updateHistory"];
319    conf.remember_errors = [prefs boolForKey:@"rememberErrors"];
320    conf.history_limit = [prefs boolForKey:@"historyLimit"];
321    conf.history_limit_len = [prefs integerForKey:@"historyLimitLen"];
322    {
323	NSDictionary *temp = [prefs dictionaryForKey:@"persistentVariables"];
324	NSEnumerator *enumerator = [temp keyEnumerator];
325	id key;
326
327	while ((key = [enumerator nextObject])) {
328	    putexp(strdup([key UTF8String]),strdup([[temp objectForKey:key] UTF8String]),"preloaded");
329	}
330    }
331    if ([prefs integerForKey:@"internalPrecision"] < 32) {
332	    [prefs setObject:@"1024" forKey:@"internalPrecision"];
333    }
334    if ([prefs integerForKey:@"internalPrecision"] > 4096) {
335	    [prefs setObject:@"4096" forKey:@"internalPrecision"];
336    }
337    init_numbers();
338    num_set_default_prec([prefs integerForKey:@"internalPrecision"]);
339    Dprintf("preferences read\n");
340
341    [PrecisionSlider setIntValue:conf.precision];
342    Dprintf("precision slider\n");
343    just_answered = FALSE;
344
345    /* Set up the character translation */
346    NSNumberFormatter *numFormat = [[[NSNumberFormatter alloc] init] autorelease];
347    if ([[numFormat decimalSeparator] length] > 0) {
348	Dprintf("NSDecimalSeparator > 0\n");
349	conf.dec_delimiter = [[numFormat decimalSeparator] characterAtIndex:0];
350    } else {
351	conf.dec_delimiter = '.';
352    }
353    Dprintf("NSDecimalSeparator set (%c)\n", conf.dec_delimiter);
354    if ([[numFormat groupingSeparator] length] > 0) {
355	Dprintf("NSGroupingSeparator > 0\n");
356	conf.thou_delimiter = [[numFormat groupingSeparator] characterAtIndex:0];
357    } else {
358	conf.thou_delimiter = 0;
359    }
360    Dprintf("NSGroupingSeparator set (%c)\n", conf.thou_delimiter);
361    if ([[prefs stringForKey:@"alternateInputDecimalSeparator"] length] > 0) {
362	conf.in_dec_delimiter = [[prefs stringForKey:@"alternateInputDecimalSeparator"] characterAtIndex:0];
363	Dprintf("alternate input dec sep (%c)\n", conf.in_dec_delimiter);
364    }
365    if ([[prefs stringForKey:@"alternateInputThousandsSeparator"] length] > 0) {
366	conf.in_thou_delimiter = [[prefs stringForKey:@"alternateInputThousandsSeparator"] characterAtIndex:0];
367	Dprintf("alternate input thou sep (%c)\n", conf.in_thou_delimiter);
368    }
369    if (conf.in_dec_delimiter != 0) {
370	[decimalKey setTitle:[NSString stringWithCString:&conf.in_dec_delimiter length:1]];
371    } else {
372	[decimalKey setTitle:[numFormat decimalSeparator]];
373	Dprintf("decimalKey title set\n");
374    }
375
376    /* reset the window to the saved setting */
377    superview = [keypad superview];
378    [keypad retain];
379    [PrecisionSlider retain];
380    [ExpressionField retain];
381    Dprintf("interface retained\n");
382    [mainWindow useOptimizedDrawing:TRUE];
383    [mainWindow setFrameAutosaveName:@"wcalc"];
384    Dprintf("frame autosave set\n");
385    w = [mainWindow frame];
386    if ([prefs boolForKey:@"toggled"]) {
387	Dprintf("window is toggled\n");
388	w.size.height += KEYPAD_HEIGHT;
389	w.origin.y -= KEYPAD_HEIGHT;
390	[mainWindow setFrame:w display:TRUE animate:FALSE];
391	Dprintf("frame set\n");
392	[self toggleSize:0];
393	Dprintf("toggled\n");
394    } else {
395	Dprintf("window not toggled\n");
396	w.size.width = MIN_WINDOW_WIDTH;
397	[mainWindow setFrame:w display:TRUE animate:FALSE];
398	bounds.width = MIN_WINDOW_WIDTH;
399	bounds.height = MIN_WINDOW_HEIGHT_UNTOGGLED;
400	[mainWindow setMinSize:bounds];
401	bounds.width = MIN_WINDOW_WIDTH;
402	bounds.height = MAX_WINDOW_SIZE;
403	[mainWindow setMaxSize:bounds];
404	Dprintf("window size restored\n");
405    }
406    //	w = [mainWindow frame];
407    //	bounds = [mainWindow minSize];
408
409    e = enterKey;
410    ef = ExpressionField;
411
412    /* this restores the drawer states */
413    if ([prefs boolForKey:@"historyShowing"]) {
414	Dprintf("history showing\n");
415	[NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(openIDrawer:) userInfo:nil repeats:NO];
416	Dprintf("history drawer displayed\n");
417    }
418    if ([prefs boolForKey:@"baseShowing"]) {
419	Dprintf("base showing\n");
420	[NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(openBDrawer:) userInfo:nil repeats:NO];
421	Dprintf("base drawer displayed\n");
422    }
423    Dprintf("done with drawers\n");
424
425    /* set the correct expression display for simple_calc */
426    if (conf.simple_calc) {
427	Dprintf("simple calc\n");
428	[ExpressionField setStringValue:@"0"];
429	[AnswerField setStringValue:@"0"];
430	Dprintf("values zeroed\n");
431	simpleClearAll();
432	Dprintf("simple all cleared\n");
433    }
434    num_init_set_ui(last_answer, 0);
435    Dprintf("last answer cleared\n");
436    pthread_mutex_init(&displayLock,NULL);
437    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(quit:) name:NSWindowWillCloseNotification object:mainWindow];
438    NSUpdateDynamicServices();
439}
440
441- (void)openBDrawer: (id) sender
442{
443    [baseDrawer open];
444    [baseMenu setTitle:@"Close Base Drawer"];
445}
446
447- (void)openIDrawer: (id) sender
448{
449    [inspector openIt:sender];
450}
451
452- (IBAction)setPrecision:(id)sender
453{
454    int last_pres=0;
455    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
456
457    last_pres = [prefs integerForKey:@"precision"];
458
459    if (last_pres == [PrecisionSlider intValue])
460	return;
461    else
462	last_pres = [PrecisionSlider intValue];
463
464    Dprintf("setPrecision: %i to %i\n",conf.precision,last_pres);
465    conf.precision = last_pres;
466    [prefs setObject:[NSString stringWithFormat:@"%i",conf.precision] forKey:@"precision"];
467    Dprintf("setPrecision - prefs set\n");
468
469    Dprintf("getting lock\n");
470    pthread_mutex_lock(&displayLock);
471    Dprintf("locked\n");
472    {
473	set_prettyanswer(last_answer);
474	Dprintf("setPrecision - set_prettyanswer\n");
475	[self displayAnswer];
476	Dprintf("setPrecision - done\n");
477    }
478    pthread_mutex_unlock(&displayLock);
479    Dprintf("unlocked\n");
480}
481
482- (IBAction)go:(id)sender
483{
484    char * expression;
485    extern char * errstring;
486
487    expression = strdup([[ExpressionField stringValue] UTF8String]);
488
489    parseme(expression);
490    putval("a",last_answer,"previous answer");
491
492    /* if it isn't an error (or if you want me to remember errors) record it in the history */
493    if (!errstring || (errstring && !strlen(errstring)) || conf.remember_errors) {
494	addToHistory(expression, last_answer);
495	free(expression);
496    }
497
498    [self displayAnswer];
499}
500
501- (void)displayAnswer
502{
503    extern char * errstring;
504
505    Dprintf("displayAnswer\n");
506    /* if there is an error, display it */
507    if (errstring && strlen(errstring)) {
508	extern int scanerror;
509	scanerror = 0;
510	Dprintf("displayAnswer error %s\n",errstring);
511	[errorController throwAlert:[NSString stringWithUTF8String:errstring]];
512	free(errstring);
513	errstring = NULL;
514    }
515    /* display the answer */
516    Dprintf("displayAnswer - pretty_answer(%p)\n",pretty_answer);
517    Dprintf("displayAnswer - %s\n",pretty_answer);
518    [AnswerField setStringValue:[NSString stringWithFormat:@"%s",pretty_answer]];
519    [AnswerField setTextColor:(not_all_displayed?[NSColor redColor]:[NSColor blackColor])];
520    Dprintf("displayAnswer - changing size\n");
521    { // Make the Answerfield big enough to display the answer
522	NSRect curFrame, newFrame;
523	curFrame = [AnswerField frame];
524	Dprintf("displayAnswer - current size: %f x %f\n", curFrame.size.height, curFrame.size.width);
525	newFrame = curFrame;
526	// we set the height to a huge number because cellSizeForBounds only
527	// works "within" the specified bound, which we want because we want to
528	// limit the width.
529	newFrame.size.height = DBL_MAX;
530	newFrame.size = [[AnswerField cell] cellSizeForBounds:newFrame];
531	Dprintf("displayAnswer - needed size: %f x %f\n", newFrame.size.height, newFrame.size.width);
532	if (curFrame.size.height != newFrame.size.height) {
533	    size_t newHeight = newFrame.size.height;
534	    int difference = newHeight - curFrame.size.height;
535	    NSRect windowFrame = [mainWindow frame];
536	    int nonAnswerPixels = windowFrame.size.height - curFrame.size.height;
537	    NSSize ms = [mainWindow minSize];
538
539	    newFrame = curFrame;
540	    newFrame.size.height = newHeight;
541	    ms.height += difference;
542	    windowFrame.size.height += difference;
543	    if (windowFrame.size.height < newFrame.size.height + nonAnswerPixels) {
544		windowFrame.size.height = newFrame.size.height + nonAnswerPixels;
545	    }
546	    windowFrame.origin.y -= difference;
547	    curFrame = [ExpressionField frame];
548	    [AnswerField setHidden:TRUE];
549	    [ExpressionField setHidden:TRUE];
550	    [mainWindow setFrame:windowFrame display:YES animate:YES];
551	    windowFrame = [mainWindow frame];
552	    /* At this point, the windowFrame may not be *quite* what I wanted it to be,
553		screens being of finite size and all... so we have to recalculate the size
554		that the AnswerField should be. */
555	    newFrame.size.height = windowFrame.size.height - nonAnswerPixels;
556	    [mainWindow setMinSize:ms];
557	    [AnswerField setFrame:newFrame];
558	    [ExpressionField setFrame:curFrame];
559	    [AnswerField setHidden:FALSE];
560	    [ExpressionField setHidden:FALSE];
561	}
562    }
563    Dprintf("displayAnswer - refresh inspector\n");
564    // if the drawer is open, refresh the data.
565    if ([inspectorWindow isVisible]) {
566	[variableList reloadData];
567	[historyList reloadData];
568    }
569    just_answered = TRUE;
570    // refresh the prefs if necessary
571    Dprintf("displayAnswer - refresh prefs\n");
572    if ([thePrefPanel isVisible])
573	[self displayPrefs:0];
574    Dprintf("displayAnswer - cleaning up\n");
575    [outputFormat2 selectCellWithTag:conf.output_format];
576    [ExpressionField selectText:self];
577    Dprintf("displayAnswer - done\n");
578}
579
580- (IBAction)convert:(id)sender
581{
582    int type = [convertType indexOfSelectedItem];
583    int from = [convertFrom selectedRow];
584    int to = [convertTo selectedRow];
585
586    if (type < 0 || type > MAX_TYPE) return;
587    if (from < 0) return;
588    if (to < 0) return;
589
590    uber_conversion(last_answer, type, from, to, last_answer);
591    set_prettyanswer(last_answer);
592    [AnswerField setStringValue:[NSString stringWithUTF8String:(pretty_answer?pretty_answer:"Not Enough Memory")]];
593    putval("a",last_answer,"previous answer");
594    if ([inspectorWindow isVisible]) {
595	[variableList reloadData];
596    }
597}
598
599- (IBAction)enterData:(id)sender
600{
601    NSString * sent = [NSString stringWithString:[[sender attributedTitle] string]];
602    static short shiftdown = 0, capsdown = 0;
603    int tag;
604
605    Dprintf("enterData\n");
606    [ExpressionField setSelectable:FALSE];
607    tag = [sender tag];
608    switch (tag) {
609	case 101: /* delete key on the onscreen keyboard */
610	    if ([[ExpressionField stringValue] length] > 0) {
611		unsigned len = [[ExpressionField stringValue] length];
612		[ExpressionField setStringValue:[[ExpressionField stringValue] substringToIndex:len-1]];
613	    }
614	    break;
615	case 100: /* clear key on the onscreen keypad */
616	    if (!conf.simple_calc) {
617		if ([[ExpressionField stringValue] length] > 0) {
618		    [ExpressionField setStringValue:@""];
619		    [ExpressionField selectText:self];
620		} else if ([[AnswerField stringValue] length] > 0) {
621		    [AnswerField setStringValue:@""];
622		    [ExpressionField selectText:self];
623		}
624	    } else {
625		if (! [[ExpressionField stringValue] isEqualToString:@"0"]) {
626		    [ExpressionField setStringValue:@"0"];
627		    [ExpressionField selectText:self];
628		    simpleClearEntry();
629		} else {
630		    [AnswerField setStringValue:@"0"];
631		    [ExpressionField selectText:self];
632		    simpleClearAll();
633		}
634	    }
635	    break;
636	case 102: /* caps lock key on onscreen keyboard */
637	    if (capsdown) {
638		[shiftKey1 setEnabled:true];
639		[shiftKey2 setEnabled:true];
640		capsdown = 0;
641	    } else {
642		[shiftKey1 setEnabled:false];
643		[shiftKey2 setEnabled:false];
644		capsdown = 1;
645	    }
646	    break;
647	case 103: /* shift key on onscreen keyboard */
648	    if (shiftdown) {
649		[shiftKey1 setState:NSOffState];
650		[shiftKey2 setState:NSOffState];
651		shiftdown = 0;
652	    } else {
653		[shiftKey1 setState:NSOnState];
654		[shiftKey2 setState:NSOnState];
655		shiftdown = 1;
656	    }
657	    break;
658	case 104: /* = key on onscreen keypad */
659	    if (! conf.simple_calc) {
660		[self go:sender];
661	    } else {
662		char * expr = strdup([[ExpressionField stringValue] UTF8String]);
663		char * ret;
664		ret = simpleCalc('=',expr);
665		if (ret) {
666		    [ExpressionField setStringValue:[NSString stringWithUTF8String:ret]];
667		    free(ret);
668		} else {
669		    [self displayAnswer];
670		    [ExpressionField setStringValue:[AnswerField stringValue]];
671		}
672		free(expr);
673	    }
674	    break;
675	case 105: /* the divide key on the onscreen keypad */
676	case 106: /* the minus key on the onscreen keypad */
677	case 107: /* the times key on the onscreen keypad */
678	default:
679	    if (! conf.simple_calc) { /* the real power of Wcalc */
680		if (just_answered == FALSE) {
681		    [ExpressionField setStringValue:[[ExpressionField stringValue] stringByAppendingString:sent]];
682		} else if ([sent isEqualToString:@"+"] ||
683			   [sent isEqualToString:@"-"] ||
684			   [sent isEqualToString:@"*"] ||
685			   [sent isEqualToString:@"/"] ||
686			   [sent isEqualToString:@"%"] ||
687			   [sent isEqualToString:@"("] ||
688			   [sent isEqualToString:@"&"] ||
689			   [sent isEqualToString:@"|"] ||
690			   [sent isEqualToString:[NSString stringWithFormat:@"%C",0x00f7]]) {
691		 [ExpressionField setStringValue:[[@"a" self] stringByAppendingString:sent]];
692		} else {
693		    [ExpressionField setStringValue:sent];
694		}
695		if (shiftdown) {
696		    [shiftKey1 setState:NSOffState];
697		    [shiftKey2 setState:NSOffState];
698		    shiftdown = 0;
699		}
700		just_answered = FALSE;
701	    } else { /* stupid calculator */
702		char *ret, *expr;
703		expr = strdup([[ExpressionField stringValue] UTF8String]);
704		Dprintf("expr: %s\n",expr);
705		switch (tag) {
706		    case 105: ret = simpleCalc('/', expr); break;
707		    case 106: ret = simpleCalc('-', expr); break;
708		    case 107: ret = simpleCalc('*', expr); break;
709		    default:  ret = simpleCalc([sent characterAtIndex:0], expr);
710		}
711		free(expr);
712		if (ret) {
713		    [ExpressionField setStringValue:[NSString stringWithUTF8String:ret]];
714		    free(ret);
715		} else {
716		    [self displayAnswer];
717		    [ExpressionField setStringValue:[AnswerField stringValue]];
718		}
719	    }
720	    break;
721    }
722    [ExpressionField setEditable:TRUE];
723}
724
725- (IBAction)shConversions:(id)sender
726{
727    static char initialized = 0;
728    if (! [conversionWindow isVisible]) {
729	[conversionWindow makeKeyAndOrderFront:self];
730	if (! initialized) {
731	    [conversionWindow center];
732	    initialized = 1;
733	}
734    } else {
735	[conversionWindow close];
736    }
737}
738
739- (IBAction)showKeyboardDrawer:(id)sender
740{
741    static char initialized = 0;
742    if (! [theKeyboard isVisible]) {
743	[theKeyboard setBecomesKeyOnlyIfNeeded:YES];
744	[theKeyboard orderFront:self];
745	if (! initialized) {
746	    [theKeyboard center];
747	    initialized = 1;
748	}
749    } else {
750	[theKeyboard close];
751    }
752}
753
754- (IBAction)showBaseDrawer:(id)sender
755{
756    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
757    if (! [baseDrawer state]) {
758	[baseDrawer open];
759	[prefs setObject:@"YES" forKey:@"baseShowing"];
760	[baseMenu setTitle:@"Close Base Drawer"];
761    } else {
762	[baseDrawer close];
763	[prefs setObject:@"NO" forKey:@"baseShowing"];
764	[baseMenu setTitle:@"Open Base Drawer"];
765    }
766}
767
768- (IBAction)setPrefs:(id)sender
769{
770    short need_redraw = 0;
771    short olde;
772    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
773    int tag = [sender tag];
774
775    switch (tag) {
776	case 1: // Flag Undefined Variables
777	    olde = conf.picky_variables;
778	    conf.picky_variables = ([pickyVariables state]==NSOnState);
779	    if (olde != conf.picky_variables) {
780		[prefs setObject:(conf.picky_variables?@"YES":@"NO") forKey:@"flagUndefinedVariables"];
781	    }
782	    break;
783	case 2: // Use Radians
784	    olde = conf.use_radians;
785	    conf.use_radians = ([useRadians state]==NSOnState);
786	    if (olde != conf.use_radians) {
787		need_redraw = 2;
788		[prefs setObject:(conf.use_radians?@"YES":@"NO") forKey:@"useRadians"];
789	    }
790	    break;
791	case 3: // Use Engineering Notation
792	    {
793		int savedas = 1;
794		olde = conf.engineering;
795		printf("index: %i\n", [sender indexOfSelectedItem]);
796		switch([sender indexOfSelectedItem]) {
797		    case 0: conf.engineering = automatic; savedas = 1; break;
798		    case 1: conf.engineering = never; savedas = 2; break;
799		    case 2: conf.engineering = always; savedas = 3; break;
800		}
801		if (olde != conf.engineering) {
802		    need_redraw = 1;
803		    printf("integet: %i\n", conf.engineering);
804		    [prefs setObject:[NSString stringWithFormat:@"%i",savedas] forKey:@"engineeringNotation"];
805		}
806	    }
807	    break;
808	case 4: // Allow Duplicates in History
809	    olde = allow_duplicates;
810	    allow_duplicates = ([historyDuplicates state]==NSOnState);
811	    if (olde != allow_duplicates) {
812		[prefs setObject:(allow_duplicates?@"YES":@"NO") forKey:@"historyDuplicatesAllowed"];
813	    }
814	    break;
815	case 5: // Output Format
816	    olde = conf.output_format;
817	    conf.output_format = [[sender selectedCell] tag];
818	    if (olde != conf.output_format) {
819		need_redraw = 1;
820		[prefs setObject:[NSString stringWithFormat:@"%i",conf.output_format] forKey:@"outputFormat"];
821		[printPrefixes setEnabled:(conf.output_format!=DECIMAL_FORMAT)];
822		[engineeringNotation setEnabled:(conf.output_format==DECIMAL_FORMAT)];
823	    }
824	    [outputFormat selectCellWithTag:conf.output_format];
825	    [outputFormat2 selectCellWithTag:conf.output_format];
826	    break;
827	case 6: // Print Prefixes
828	    olde = conf.print_prefixes;
829	    conf.print_prefixes = ([sender state]==NSOnState);
830	    if (olde != conf.print_prefixes) {
831		need_redraw = 1;
832		[prefs setObject:(conf.print_prefixes?@"YES":@"NO") forKey:@"printPrefixes"];
833	    }
834	    break;
835	case 7: // Update History
836	    olde = update_history;
837	    update_history = ([sender state]==NSOnState);
838	    if (olde != update_history) {
839		[prefs setObject:(update_history?@"YES":@"NO") forKey:@"updateHistory"];
840	    }
841	    break;
842	case 10: // Rounding Indication
843	    olde = conf.rounding_indication;
844	    conf.rounding_indication = [sender indexOfSelectedItem];
845	    if (olde != conf.rounding_indication) {
846		need_redraw = 1;
847		[prefs setObject:[NSString stringWithFormat:@"%i",conf.rounding_indication] forKey:@"roundingIndication"];
848	    }
849	    break;
850	case 11: // Record errors in history
851	    olde = conf.remember_errors;
852	    conf.remember_errors = ([sender state]==NSOnState);
853	    if (olde != conf.remember_errors) {
854		[prefs setObject:(conf.remember_errors?@"YES":@"NO") forKey:@"rememberErrors"];
855	    }
856	    break;
857	case 12: // Conservative precision
858	    olde = conf.precision_guard;
859	    conf.precision_guard = ([sender state]==NSOnState);
860	    if (olde != conf.precision_guard) {
861		need_redraw = 2;
862		[prefs setObject:(conf.precision_guard?@"YES":@"NO") forKey:@"precisionGuard"];
863	    }
864	    break;
865	case 13: // History length limit toggle
866	    olde = conf.history_limit;
867	    conf.history_limit = ([sender state]==NSOnState);
868	    [limitHistoryLen setEnabled:conf.history_limit];
869	    [limitHistoryLenTag setEnabled:conf.history_limit];
870	    if (olde != conf.history_limit) {
871		[prefs setObject:(conf.history_limit?@"YES":@"NO") forKey:@"historyLimit"];
872	    }
873	    break;
874	case 14: // History length limit
875	    if ((unsigned)[sender intValue] != conf.history_limit_len) {
876		conf.history_limit_len = [sender intValue];
877		[prefs setObject:[NSString stringWithFormat:@"%i",conf.history_limit_len] forKey:@"historyLimitLength"];
878	    }
879	    break;
880	case 15: // Print ints
881	    olde = conf.print_ints;
882	    conf.print_ints = ([sender state]==NSOnState);
883	    if (olde != conf.print_ints) {
884		need_redraw = 1;
885		[prefs setObject:(conf.print_ints?@"YES":@"NO") forKey:@"printInts"];
886	    }
887	    break;
888	case 16: // Simple calculator
889	    olde = conf.simple_calc;
890	    conf.simple_calc = ([sender state]==NSOnState);
891	    if (olde != conf.simple_calc) {
892		[prefs setObject:(conf.simple_calc?@"YES":@"NO") forKey:@"simpleCalc"];
893		if (conf.simple_calc) {
894		    [ExpressionField setStringValue:@"0"];
895		    [AnswerField setStringValue:@"0"];
896		    simpleClearAll();
897		} else {
898		    [ExpressionField setStringValue:@""];
899		    [AnswerField setStringValue:@""];
900		}
901		/* disable irrelevant preferences */
902		[historyDuplicates setEnabled:!conf.simple_calc];
903		[limitHistory setEnabled:!conf.simple_calc];
904		[limitHistoryLen setEnabled:!conf.simple_calc];
905		[limitHistoryLenTag setEnabled:!conf.simple_calc];
906		[pickyVariables setEnabled:!conf.simple_calc];
907		[rememberErrors setEnabled:!conf.simple_calc];
908		[updateHistory setEnabled:!conf.simple_calc];
909		[useRadians setEnabled:!conf.simple_calc];
910	    }
911	    break;
912	case 17:
913	    olde = conf.print_commas;
914	    conf.print_commas = ([sender state]==NSOnState);
915	    if (olde != conf.print_commas) {
916		need_redraw = 1;
917		[prefs setObject:(conf.print_ints?@"YES":@"NO") forKey:@"printDelimiters"];
918	    }
919	    break;
920	case 18:
921	    if ((unsigned)[sender intValue] != num_get_default_prec()) {
922		[bitsStepper takeIntValueFrom:sender];
923		num_set_default_prec([bitsStepper intValue]); // to handle limits placed on bitsStepper
924		[prefs setObject:[NSString stringWithFormat:@"%lu",num_get_default_prec()] forKey:@"internalPrecision"];
925	    }
926	    break;
927	case 19:
928	    if ((unsigned)[bitsStepper intValue] != num_get_default_prec()) {
929		num_set_default_prec([bitsStepper intValue]);
930		need_redraw = 2;
931		[bitsPref takeIntValueFrom:bitsStepper];
932		[prefs setObject:[NSString stringWithFormat:@"%lu",num_get_default_prec()] forKey:@"internalPrecision"];
933	    }
934	    break;
935	case 20:
936	    olde = conf.live_precision;
937	    conf.live_precision = ([sender state] == NSOnState);
938	    if (olde != conf.print_commas) {
939		[prefs setObject:(conf.live_precision?@"YES":@"NO") forKey:@"livePrecision"];
940		[PrecisionSlider setContinuous:(conf.live_precision?true:false)];
941	    }
942	    break;
943	case 21:
944	    olde = conf.c_style_mod;
945	    conf.c_style_mod = ([sender state] == NSOnState);
946	    if (olde != conf.c_style_mod) {
947		need_redraw = 2;
948		[prefs setObject:(conf.c_style_mod?@"YES":@"NO") forKey:@"cModStyle"];
949	    }
950	    break;
951	case 22:
952	    if ((unsigned)[sliderStepper intValue] != [PrecisionSlider maxValue]) {
953		unsigned long tmp = [sliderStepper intValue];
954		[PrecisionSlider setMaxValue:(double)tmp];
955		[sliderPref takeIntValueFrom:sliderStepper];
956		[prefs setObject:[NSString stringWithFormat:@"%lu",tmp] forKey:@"maxSliderPrecision"];
957	    }
958	    break;
959	case 23:
960	    if ((double)[sender intValue] != [PrecisionSlider maxValue]) {
961		[sliderStepper takeIntValueFrom:sender];
962		// these handle limits placed on sliderStepper
963		[sliderPref takeIntValueFrom:sliderStepper];
964		[PrecisionSlider setMaxValue:[sliderStepper doubleValue]];
965		[prefs setObject:[NSString stringWithFormat:@"%lu",[sliderStepper intValue]] forKey:@"maxSliderPrecision"];
966	    }
967	    break;
968	case 24:
969	    [altInputDecSep setEnabled:([sender state] == NSOnState)];
970	    [altInputThouSep setEnabled:([sender state] == NSOnState)];
971	    if ([sender state] != NSOnState) {
972		[altInputDecSep setStringValue:@""];
973		[altInputThouSep setStringValue:@""];
974		conf.in_dec_delimiter = 0;
975		conf.in_thou_delimiter = 0;
976		[decimalKey setTitle:[NSString stringWithCString:&conf.dec_delimiter length:1]];
977		[prefs setObject:@"" forKey:@"alternateInputDecimalSeparator"];
978		[prefs setObject:@"" forKey:@"alternateInputThousandsSeparator"];
979	    }
980	    break;
981	case 25:
982	    if ([[sender stringValue] length] > 0) {
983		conf.in_dec_delimiter = [[sender stringValue] characterAtIndex:0];
984		[decimalKey setTitle:[NSString stringWithCString:&conf.in_dec_delimiter length:1]];
985		[prefs setObject:[[sender stringValue] substringToIndex:1] forKey:@"alternateInputDecimalSeparator"];
986	    } else {
987		conf.in_dec_delimiter = 0;
988		[decimalKey setTitle:[NSString stringWithCString:&conf.dec_delimiter length:1]];
989		[prefs setObject:@"" forKey:@"alternateInputDecimalSeparator"];
990	    }
991	    break;
992	case 26:
993	    if ([[sender stringValue] length] > 0) {
994		conf.in_thou_delimiter = [[sender stringValue] characterAtIndex:0];
995		[prefs setObject:[[sender stringValue] substringToIndex:1] forKey:@"alternateInputThousandsSeparator"];
996	    } else {
997		conf.in_thou_delimiter = 0;
998		[prefs setObject:@"" forKey:@"alternateInputThousandsSeparator"];
999	    }
1000	    break;
1001	default: return;
1002    }
1003
1004    switch (need_redraw) {
1005	case 2:
1006	    if (update_history)
1007		recalculate = 1;
1008	    [self go:sender];
1009	    break;
1010	case 1:
1011	    set_prettyanswer(last_answer);
1012	    [AnswerField setStringValue:[NSString stringWithUTF8String:(pretty_answer?pretty_answer:"Not Enough Memory")]];
1013	    [AnswerField setTextColor:((not_all_displayed)?([NSColor redColor]):([NSColor blackColor]))];
1014	    break;
1015    }
1016    if ([inspectorWindow isVisible] || recalculate) {
1017	[historyList reloadData];
1018    }
1019    [ExpressionField selectText:self];
1020}
1021
1022- (IBAction)showPrefs:(id)sender
1023{
1024    //static char initialized = 0;
1025    [self displayPrefs:sender];
1026    [thePrefPanel setBecomesKeyOnlyIfNeeded:TRUE];
1027    [thePrefPanel orderFront:self];
1028    // centering at first
1029    /*if (! initialized) {
1030	initialized=1;
1031	[thePrefPanel center];
1032    }*/
1033    // this should be redundant
1034    [thePrefPanel setFrameAutosaveName:@"wcalc_prefs"];
1035    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(savePrefs:) name:NSWindowWillCloseNotification object:thePrefPanel];
1036}
1037
1038- (IBAction)savePrefs:(id)sender
1039{
1040    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
1041
1042    Dprintf("synching the prefs to disk\n");
1043    [prefs synchronize];
1044}
1045
1046- (IBAction)open:(id)sender
1047{
1048    int result;
1049    NSArray *fileTypes = [NSArray arrayWithObjects:@"txt",@"text",@"wcalc",
1050	    NSFileTypeForHFSTypeCode('TEXT'), nil];
1051    NSOpenPanel *oPanel = [NSOpenPanel openPanel];
1052    [oPanel setAllowsMultipleSelection:NO];
1053    /* display the panel */
1054    result = [oPanel runModalForDirectory:nil file:nil types:fileTypes];
1055    /* if they clicked the OK button */
1056    if (result == NSOKButton) {
1057	NSArray *filesToOpen = [oPanel filenames];
1058	int i, count = [filesToOpen count];
1059	/* loop through the files to open (there should only be one, but
1060	   it's good to be able to handle multiple anyway */
1061	for (i=0; i<count; i++) {
1062	    int retval;
1063	    extern char * errstring;
1064	    curFile = [filesToOpen objectAtIndex:i];
1065	    retval = loadState(strdup([curFile UTF8String]),1);
1066	    if ([inspectorWindow isVisible]) {
1067		[variableList reloadData];
1068		[historyList reloadData];
1069	    }
1070	    /* if there is an error, display it */
1071	    if (errstring && strlen(errstring)) {
1072		extern int scanerror;
1073		scanerror = 0;
1074		[errorController throwAlert:[NSString stringWithUTF8String:errstring]];
1075		free(errstring);
1076		errstring = NULL;
1077	    }
1078	    // refresh the prefs if necessary
1079	    if ([thePrefPanel isVisible])
1080		[self displayPrefs:sender];
1081	    [outputFormat2 selectCellWithTag:conf.output_format];
1082	    if (retval)
1083		[self displayErrno:retval forFile:curFile];
1084	}
1085    }
1086}
1087
1088- (void)displayErrno:(int)err forFile:(NSString*)filename
1089{
1090    char * errstr;
1091    errstr = malloc(strlen(strerror(errno))+[filename length]+3);
1092    sprintf(errstr,"%s: %s",[filename UTF8String], strerror(errno));
1093    [errorController throwAlert:[NSString stringWithUTF8String:errstr]];
1094    free(errstr);
1095}
1096
1097- (IBAction)saveAs:(id)sender
1098{
1099    NSSavePanel *sp;
1100    int runResult;
1101    /* create or get the shared instance of NSSavePanel */
1102    sp = [NSSavePanel savePanel];
1103    /* set up new attributes */
1104    //	[sp setAccessoryView:newView];
1105    [sp setRequiredFileType:@"txt"];
1106    /* display the NSSavePanel */
1107    runResult = [sp runModalForDirectory:nil file:@""];
1108    /* if successful, save file under designated name */
1109    if (runResult == NSOKButton) {
1110	curFile = [sp filename];
1111	[self save:sender];
1112	//		if (![textData writeToFile:[sp filename] atomically:YES])
1113	//			NSBeep();
1114    }
1115}
1116
1117- (BOOL)validateMenuItem:(NSMenuItem *)anItem
1118{
1119    switch ([anItem tag]) {
1120	case 1001: // save
1121	case 1002: // save as
1122	    if (historyLength()) return YES;
1123	    else return NO;
1124	    break;
1125	default:
1126	    return YES;
1127    }
1128}
1129
1130- (IBAction)save:(id)sender
1131{
1132    if (! curFile) {
1133	[self saveAs:sender];
1134    } else {
1135	int retval;
1136	retval = saveState(strdup([curFile UTF8String]));
1137	if (retval)
1138	    [self displayErrno:retval forFile:curFile];
1139    }
1140}
1141
1142- (IBAction)displayPrefs:(id)sender
1143{
1144    switch (conf.engineering) {
1145	case automatic: [engineeringNotation selectItemAtIndex:0]; break;
1146	case never: [engineeringNotation selectItemAtIndex:1]; break;
1147	case always: [engineeringNotation selectItemAtIndex:2]; break;
1148    }
1149    [pickyVariables setState:(conf.picky_variables?NSOnState:NSOffState)];
1150    [historyDuplicates setState:(allow_duplicates?NSOnState:NSOffState)];
1151    [useRadians setState:(conf.use_radians?NSOnState:NSOffState)];
1152    [outputFormat selectCellWithTag:conf.output_format];
1153    [printPrefixes setState:(conf.print_prefixes?NSOnState:NSOffState)];
1154    [roundingIndication selectItemAtIndex:conf.rounding_indication];
1155    [rememberErrors setState:(conf.remember_errors?NSOnState:NSOffState)];
1156    [limitHistory setState:(conf.history_limit?NSOnState:NSOffState)];
1157    [printInts setState:(conf.print_ints?NSOnState:NSOffState)];
1158    [precisionGuard setState:(conf.precision_guard?NSOnState:NSOffState)];
1159    [simpleCalculator setState:(conf.simple_calc?NSOnState:NSOffState)];
1160    [printDelimiters setState:(conf.print_commas?NSOnState:NSOffState)];
1161    [bitsPref setIntValue:num_get_default_prec()];
1162    [bitsStepper setIntValue:num_get_default_prec()];
1163    [livePrecision setState:(conf.live_precision?NSOnState:NSOffState)];
1164    [cModPref setState:(conf.c_style_mod?NSOnState:NSOffState)];
1165    [sliderPref setIntValue:(int)[PrecisionSlider maxValue]];
1166    [sliderStepper setIntValue:(int)[PrecisionSlider maxValue]];
1167    [alternateInputPref setState:(conf.in_dec_delimiter != 0 || conf.in_thou_delimiter != 0)];
1168
1169    /* disable irrelevant preferences */
1170    [historyDuplicates setEnabled:!conf.simple_calc];
1171    [limitHistory setEnabled:!conf.simple_calc];
1172    [pickyVariables setEnabled:!conf.simple_calc];
1173    [rememberErrors setEnabled:!conf.simple_calc];
1174    [updateHistory setEnabled:!conf.simple_calc];
1175    [useRadians setEnabled:!conf.simple_calc];
1176    [printPrefixes setEnabled:(conf.output_format!=DECIMAL_FORMAT)];
1177    [engineeringNotation setEnabled:(conf.output_format==DECIMAL_FORMAT)];
1178    [limitHistoryLen setEnabled:conf.history_limit&&!conf.simple_calc];
1179    [limitHistoryLenTag setEnabled:conf.history_limit&&!conf.simple_calc];
1180    [altInputDecSep setEnabled:[alternateInputPref state]];
1181    [altInputThouSep setEnabled:[alternateInputPref state]];
1182
1183    [limitHistoryLen setStringValue:[NSString stringWithFormat:@"%lu",conf.history_limit_len]];
1184    if ([alternateInputPref state]) {
1185	[altInputDecSep setStringValue:[NSString stringWithFormat:@"%c",conf.in_dec_delimiter]];
1186	[altInputThouSep setStringValue:[NSString stringWithFormat:@"%c",conf.in_thou_delimiter]];
1187    }
1188}
1189
1190- (IBAction)closeWindow:(id)sender
1191{
1192    if ([inspectorWindow isKeyWindow]) {
1193	[inspectorWindow close];
1194    } else if ([persVarsWindow isKeyWindow]) {
1195	[persVarsWindow close];
1196    } else if ([mainWindow isKeyWindow]) {
1197	[mainWindow close];
1198    }
1199}
1200
1201- (IBAction)quit:(id)sender
1202{
1203    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
1204
1205    [prefs synchronize];
1206    clearHistory();
1207    cleanupvar();
1208    if (pretty_answer) {
1209	extern char *pa;
1210	free(pretty_answer);
1211	if (pa) {
1212	    free(pa);
1213	}
1214    }
1215    num_free(last_answer);
1216    lists_cleanup();
1217    pthread_mutex_destroy(&displayLock);
1218    exit(EXIT_SUCCESS);
1219}
1220
1221@end
1222