1//
2//  ZoomPreferenceWindow.m
3//  ZoomCocoa
4//
5//  Created by Andrew Hunter on Sat Dec 20 2003.
6//  Copyright (c) 2003 Andrew Hunter. All rights reserved.
7//
8
9// Modifications by Collin Pieper to add transparency support
10
11#import "ZoomPreferenceWindow.h"
12#import "ZoomStoryOrganiser.h"
13
14
15static NSToolbarItem* generalSettingsItem;
16static NSToolbarItem* gameSettingsItem;
17static NSToolbarItem* displaySettingsItem;
18static NSToolbarItem* fontSettingsItem;
19static NSToolbarItem* colourSettingsItem;
20static NSToolbarItem* typographicSettingsItem;
21
22static NSDictionary*  itemDictionary = nil;
23
24@implementation ZoomPreferenceWindow
25
26+ (void) initialize {
27	// Create the toolbar items
28	generalSettingsItem = [[NSToolbarItem alloc] initWithItemIdentifier: @"generalSettings"];
29	gameSettingsItem = [[NSToolbarItem alloc] initWithItemIdentifier: @"gameSettings"];
30	displaySettingsItem = [[NSToolbarItem alloc] initWithItemIdentifier: @"displaySettings"];
31	fontSettingsItem = [[NSToolbarItem alloc] initWithItemIdentifier: @"fontSettings"];
32	colourSettingsItem = [[NSToolbarItem alloc] initWithItemIdentifier: @"colourSettings"];
33	typographicSettingsItem = [[NSToolbarItem alloc] initWithItemIdentifier: @"typographicSettings"];
34
35	// ... and the dictionary
36	itemDictionary = [[NSDictionary dictionaryWithObjectsAndKeys:
37		generalSettingsItem, @"generalSettings",
38		gameSettingsItem, @"gameSettings",
39		displaySettingsItem, @"displaySettings",
40		fontSettingsItem, @"fontSettings",
41		colourSettingsItem, @"colourSettings",
42		typographicSettingsItem, @"typographicSettings",
43		nil] retain];
44
45	// Set up the items
46	[generalSettingsItem setLabel: @"General"];
47	[generalSettingsItem setImage: [[[NSImage alloc] initWithContentsOfFile: [[NSBundle mainBundle] pathForImageResource: @"generalSettings"]] autorelease]];
48	[gameSettingsItem setLabel: @"Game"];
49	[gameSettingsItem setImage: [[[NSImage alloc] initWithContentsOfFile: [[NSBundle mainBundle] pathForImageResource: @"gameSettings"]] autorelease]];
50	[displaySettingsItem setLabel: @"Display"];
51	[displaySettingsItem setImage: [[[NSImage alloc] initWithContentsOfFile: [[NSBundle mainBundle] pathForImageResource: @"displaySettings"]] autorelease]];
52	[fontSettingsItem setLabel: @"Fonts"];
53	[fontSettingsItem setImage: [[[NSImage alloc] initWithContentsOfFile: [[NSBundle mainBundle] pathForImageResource: @"fontSettings"]] autorelease]];
54	[colourSettingsItem setLabel: @"Colour"];
55	[colourSettingsItem setImage: [[[NSImage alloc] initWithContentsOfFile: [[NSBundle mainBundle] pathForImageResource: @"colourSettings"]] autorelease]];
56	[typographicSettingsItem setLabel: @"Typography"];
57	[typographicSettingsItem setImage: [[[NSImage alloc] initWithContentsOfFile: [[NSBundle mainBundle] pathForImageResource: @"typographicSettings"]] autorelease]];
58
59	// And the actions
60	[generalSettingsItem setAction: @selector(generalSettings:)];
61	[gameSettingsItem setAction: @selector(gameSettings:)];
62	[displaySettingsItem setAction: @selector(displaySettings:)];
63	[fontSettingsItem setAction: @selector(fontSettings:)];
64	[colourSettingsItem setAction: @selector(colourSettings:)];
65	[typographicSettingsItem setAction: @selector(typographicSettings:)];
66}
67
68- (id) init {
69	return [self initWithWindowNibName: @"Preferences"];
70}
71
72- (void) dealloc {
73	if (toolbar) [toolbar release];
74	if (prefs) [prefs release];
75
76	[[NSNotificationCenter defaultCenter] removeObserver: self];
77
78	[super dealloc];
79}
80
81static int familyComparer(id a, id b, void* context) {
82	NSString* family1 = a;
83	NSString* family2 = b;
84
85	return [family1 caseInsensitiveCompare: family2];
86}
87
88- (NSMenu*) fontMenu: (BOOL) fixed {
89	// Constructs a menu of fonts
90	// (Apple want us to use the font selection panel, but it feels clunky for the 'simple' view: there's no good way to associate
91	// it with the style we're selecting. Plus we want to select families, not individual fonts)
92	NSFontManager* mgr = [NSFontManager sharedFontManager];
93
94	NSMenu* result = [[NSMenu alloc] init];
95
96	// Iterate through the available font families and create menu items
97	NSEnumerator* familyEnum = [[[mgr availableFontFamilies] sortedArrayUsingFunction: familyComparer
98																			  context: nil] objectEnumerator];
99	NSString* family;
100
101	while (family = [familyEnum nextObject]) {
102		// Get the font
103		NSFont* sampleFont = [mgr fontWithFamily: family
104										  traits: 0
105										  weight: 5
106											size: 13.0];
107
108		if (!sampleFont) continue;
109		if (fixed && ![sampleFont isFixedPitch]) {
110			// Skip this font
111			continue;
112		}
113
114		// Construct the item
115		NSMenuItem* fontItem = [[NSMenuItem alloc] init];
116		[fontItem setAttributedTitle:
117			[[[NSAttributedString alloc] initWithString: family
118											 attributes: [NSDictionary dictionaryWithObject: sampleFont
119																					 forKey: NSFontAttributeName]] autorelease]];
120
121		// Add to the menu
122		[result addItem: [fontItem autorelease]];
123	}
124
125	// Return the result
126	return [result autorelease];
127}
128
129- (void) windowDidLoad {
130	// Set the toolbar
131	toolbar = [[NSToolbar allocWithZone: [self zone]] initWithIdentifier: @"preferencesToolbar2"];
132
133	[toolbar setDelegate: self];
134	[toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
135	[toolbar setAllowsUserCustomization: NO];
136
137	[[self window] setToolbar: toolbar];
138
139	[[self window] setContentSize: [generalSettingsView frame].size];
140	[[self window] setContentView: generalSettingsView];
141
142	if ([toolbar respondsToSelector: @selector(setSelectedItemIdentifier:)]) {
143		[toolbar setSelectedItemIdentifier: @"generalSettings"];
144	}
145
146
147	[fonts setDataSource: self];
148	[fonts setDelegate: self];
149	[colours setDataSource: self];
150	[colours setDelegate: self];
151
152	// Set up the various font menus
153	NSMenu* proportionalMenu = [self fontMenu: NO];
154	NSMenu* fixedMenu = [self fontMenu: YES];
155	NSMenu* symbolMenu = [[proportionalMenu copy] autorelease];
156
157	[proportionalFont setMenu: proportionalMenu];
158	[fixedFont setMenu: fixedMenu];
159	[symbolicFont setMenu: symbolMenu];
160
161	[[NSNotificationCenter defaultCenter] addObserver: self
162											 selector: @selector(storyProgressChanged:)
163												 name: ZoomStoryOrganiserProgressNotification
164											   object: [ZoomStoryOrganiser sharedStoryOrganiser]];
165}
166
167// == Setting the pane that's being displayed ==
168
169- (void) switchToPane: (NSView*) preferencePane {
170	if ([[self window] contentView] == preferencePane) return;
171
172	// Select the appropriate item in the toolbar
173	if ([toolbar respondsToSelector: @selector(setSelectedItemIdentifier:)]) {
174		NSString* selected = nil;
175
176		if (preferencePane == generalSettingsView) {
177			selected = @"generalSettings";
178		} else if (preferencePane == gameSettingsView) {
179			selected = @"gameSettings";
180		} else if (preferencePane == displaySettingsView) {
181			selected = @"displaySettings";
182		} else if (preferencePane == fontSettingsView) {
183			selected = @"fontSettings";
184		} else if (preferencePane == colourSettingsView) {
185			selected = @"colourSettings";
186		} else if (preferencePane == typographicalSettingsView) {
187			selected = @"typographicSettings";
188		}
189
190		if (selected != nil) {
191			[toolbar setSelectedItemIdentifier: selected];
192		}
193	}
194
195	// Work out the various frame sizes
196	NSRect currentFrame = [[[self window] contentView] frame];
197	NSRect oldFrame = currentFrame;
198	NSRect windowFrame = [[self window] frame];
199
200	currentFrame.origin.y    -= [preferencePane frame].size.height - currentFrame.size.height;
201	currentFrame.size.height  = [preferencePane frame].size.height;
202
203	// Grr, complicated, as OS X provides no way to work out toolbar proportions except in 10.3
204	windowFrame.origin.x    += (currentFrame.origin.x - oldFrame.origin.x);
205	windowFrame.origin.y    += (currentFrame.origin.y - oldFrame.origin.y);
206	windowFrame.size.width  += (currentFrame.size.width - oldFrame.size.width);
207	windowFrame.size.height += (currentFrame.size.height - oldFrame.size.height);
208
209	[[self window] setContentView: [[[NSView alloc] init] autorelease]];
210	[[self window] setFrame: windowFrame
211					display: YES
212					animate: YES];
213	[[self window] setContentView: preferencePane];
214	[[self window] setInitialFirstResponder: preferencePane];
215}
216
217// == Toolbar delegate functions ==
218
219- (NSToolbarItem *)toolbar: (NSToolbar *) toolbar
220     itemForItemIdentifier: (NSString *)  itemIdentifier
221 willBeInsertedIntoToolbar: (BOOL)        flag {
222    return [itemDictionary objectForKey: itemIdentifier];
223}
224
225- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar {
226    return [NSArray arrayWithObjects:
227		@"generalSettings", @"gameSettings", @"displaySettings", @"fontSettings", @"typographicSettings", @"colourSettings", NSToolbarFlexibleSpaceItemIdentifier,
228		nil];
229}
230
231- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar {
232    return [NSArray arrayWithObjects:
233		NSToolbarFlexibleSpaceItemIdentifier, @"generalSettings", @"gameSettings", @"displaySettings", @"fontSettings", @"typographicSettings", @"colourSettings", NSToolbarFlexibleSpaceItemIdentifier,
234		nil];
235}
236
237- (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar {
238    return [NSArray arrayWithObjects:
239		@"generalSettings", @"gameSettings", @"displaySettings", @"fontSettings", @"colourSettings", @"typographicSettings",
240		nil];
241}
242
243// == Toolbar actions ==
244
245- (void) generalSettings: (id) sender {
246	[self switchToPane: generalSettingsView];
247}
248
249- (void) gameSettings: (id) sender {
250	[self switchToPane: gameSettingsView];
251}
252
253- (void) displaySettings: (id) sender {
254	[self switchToPane: displaySettingsView];
255}
256
257- (void) fontSettings: (id) sender {
258	[self switchToPane: fontSettingsView];
259}
260
261- (void) colourSettings: (id) sender {
262	[self switchToPane: colourSettingsView];
263}
264
265- (void) typographicSettings: (id) sender {
266	[self switchToPane: typographicalSettingsView];
267}
268
269// == Setting the preferences that we're editing ==
270
271- (void) setButton: (NSPopUpButton*) button
272	  toFontFamily: (NSString*) family {
273	NSMenuItem* familyItem = nil;
274	NSEnumerator* itemEnum = [[[button menu] itemArray] objectEnumerator];
275	NSMenuItem* curItem;
276
277	while (curItem = [itemEnum nextObject]) {
278		if ([[curItem title] caseInsensitiveCompare: family] == NSEqualToComparison) {
279			familyItem = curItem;
280			break;
281		}
282	}
283
284	if (familyItem) {
285		[button selectItem: familyItem];
286	}
287}
288
289- (void) setSimpleFonts {
290	// Sets our display from the 'simple' fonts the user has selected
291
292	// Select the fonts
293	[self setButton: proportionalFont
294	   toFontFamily: [prefs proportionalFontFamily]];
295	[self setButton: fixedFont
296	   toFontFamily: [prefs fixedFontFamily]];
297	[self setButton: symbolicFont
298	   toFontFamily: [prefs symbolicFontFamily]];
299
300	// Set the size display
301	float fontSize = [prefs fontSize];
302	[fontSizeSlider setFloatValue: fontSize];
303	[fontSizeDisplay setStringValue: [NSString stringWithFormat: @"%.1fpt", fontSize]];
304
305	// Set the font preview
306	[fontPreview setFont: [[prefs fonts] objectAtIndex: 0]];
307}
308
309- (NSString*) colourNameAtIndex: (int) index {
310	switch (index) {
311		case 0: return @"Black";
312		case 1: return @"Red";
313		case 2: return @"Green";
314		case 3: return @"Yellow";
315		case 4: return @"Blue";
316		case 5: return @"Magenta";
317		case 6: return @"Cyan";
318		case 7: return @"White";
319		case 8: return @"Light grey";
320		case 9: return @"Medium grey";
321		case 10: return @"Dark grey";
322		default: return @"Unused colour";
323	}
324}
325
326- (void) selectItemWithTag: (int) tag
327				   inPopup: (NSPopUpButton*) button {
328	int index;
329
330	for (index=0; index < [[button itemArray] count]; index++) {
331		if ([[button itemAtIndex: index] tag] == tag) {
332			[button selectItemAtIndex: index];
333			return;
334		}
335	}
336}
337
338- (void) updateColourMenus {
339	NSMenu* newColourMenu = [[[NSMenu alloc] init] autorelease];
340
341	int col;
342	for (col=0; col<10; col++) {
343		// Build the image showing a preview of this colour
344		NSImage* sampleImage = [[NSImage alloc] initWithSize: NSMakeSize(16, 12)];
345
346		[sampleImage lockFocus];
347		[[[prefs colours] objectAtIndex: col] set];
348		NSRectFill(NSMakeRect(0,0,16,12));
349		[sampleImage unlockFocus];
350
351		// Build the actual menu item
352		NSMenuItem* colourItem = [[NSMenuItem alloc] initWithTitle: [self colourNameAtIndex: col]
353															action: nil
354													 keyEquivalent: @""];
355		[colourItem setTag: col];
356		[colourItem setImage: sampleImage];
357
358		// Add it to the menu
359		[newColourMenu addItem: colourItem];
360
361		// Release our resources
362		[colourItem autorelease];
363		[sampleImage autorelease];
364	}
365
366	// Set the menu as the menu for both the popup buttons
367	[foregroundColour setMenu: newColourMenu];
368	[backgroundColour setMenu: [[newColourMenu copy] autorelease]];
369
370	[self selectItemWithTag: [prefs foregroundColour]
371					inPopup: foregroundColour];
372	[self selectItemWithTag: [prefs backgroundColour]
373					inPopup: backgroundColour];
374}
375
376- (void) setPreferences: (ZoomPreferences*) preferences {
377	if (prefs) [prefs release];
378	prefs = [preferences retain];
379
380	[displayWarnings setState: [prefs displayWarnings]?NSOnState:NSOffState];
381	[fatalWarnings setState: [prefs fatalWarnings]?NSOnState:NSOffState];
382	[speakGameText setState: [prefs speakGameText]?NSOnState:NSOffState];
383	[scrollbackLength setFloatValue: [prefs scrollbackLength]];
384	[keepGamesOrganised setState: [prefs keepGamesOrganised]?NSOnState:NSOffState];
385	[autosaveGames setState: [prefs autosaveGames]?NSOnState:NSOffState];
386	[reorganiseGames setEnabled: [prefs keepGamesOrganised]];
387	[confirmGameClose setState: [prefs confirmGameClose]?NSOnState:NSOffState];
388	[glulxInterpreter selectItemAtIndex: [glulxInterpreter indexOfItemWithTag: [prefs glulxInterpreter]]];
389
390	// a kind of chessy way to get the current alpha setting
391	float red, green, blue, alpha;
392	NSColor * color = [[prefs colours] objectAtIndex:0];
393	[color getRed:&red green:&green blue:&blue alpha:&alpha];
394	[transparencySlider setFloatValue:(alpha * 100.0)];
395
396	[interpreter selectItemAtIndex: [prefs interpreter]-1];
397	[revision setStringValue: [NSString stringWithFormat: @"%c", [prefs revision]]];
398
399	[self setSimpleFonts];
400
401	[organiseDir setString: [prefs organiserDirectory]];
402
403	[showMargins setState: [prefs textMargin] > 0?NSOnState:NSOffState];
404	[useScreenFonts setState: [prefs useScreenFonts]?NSOnState:NSOffState];
405	[useHyphenation setState: [prefs useHyphenation]?NSOnState:NSOffState];
406	[kerning setState: [prefs useKerning]?NSOnState:NSOffState];
407	[ligatures setState: [prefs useLigatures]?NSOnState:NSOffState];
408
409	[marginWidth setEnabled: [prefs textMargin] > 0];
410	if ([prefs textMargin] > 0) {
411		[marginWidth setFloatValue: [prefs textMargin]];
412	}
413
414	[zoomBorders setState: [prefs showBorders]?NSOnState:NSOffState];
415	[showCoverPicture setState: [prefs showCoverPicture]?NSOnState:NSOffState];
416	[self updateColourMenus];
417}
418
419// == Table data source ==
420
421- (int)numberOfRowsInTableView: (NSTableView *)aTableView {
422	if (aTableView == fonts) return [[prefs fonts] count];
423	if (aTableView == colours) return [[prefs colours] count];
424
425	return 0;
426}
427
428static void appendStyle(NSMutableString* styleName,
429						NSString* newStyle) {
430	if ([styleName length] == 0) {
431		[styleName appendString: newStyle];
432	} else {
433		[styleName appendString: @"-"];
434		[styleName appendString: newStyle];
435	}
436}
437
438- (id)              tableView:(NSTableView *)aTableView
439    objectValueForTableColumn:(NSTableColumn *)aTableColumn
440						  row:(int)rowIndex {
441	if (aTableView == fonts) {
442		// Fonts table
443		NSArray* fontArray = [prefs fonts];
444
445		if ([[aTableColumn identifier] isEqualToString: @"Style"]) {
446			NSMutableString* name = [[@"" mutableCopy] autorelease];
447
448			if (rowIndex&1) appendStyle(name, @"bold");
449			if (rowIndex&2) appendStyle(name, @"italic");
450			if (rowIndex&4) appendStyle(name, @"fixed");
451			if (rowIndex&8) appendStyle(name, @"symbolic");
452
453			if ([name isEqualToString: @""]) name = [[@"roman" mutableCopy] autorelease];
454
455			return name;
456		} else if ([[aTableColumn identifier] isEqualToString: @"Font"]) {
457			NSString* fontName;
458			NSFont* font = [fontArray objectAtIndex: rowIndex];
459
460			fontName = [NSString stringWithFormat: @"%@ (%.2gpt)",
461				[font fontName],
462				[font pointSize]];
463
464			NSAttributedString* res;
465
466			res = [[[NSAttributedString alloc] initWithString: fontName
467												   attributes: [NSDictionary dictionaryWithObject: font
468																						   forKey: NSFontAttributeName]]
469				autorelease];
470
471			return res;
472		}
473
474		return @" -- ";
475	}
476
477	if (aTableView == colours) {
478		if ([[aTableColumn identifier] isEqualToString: @"Colour name"]) {
479			return [self colourNameAtIndex: rowIndex];
480		} else if ([[aTableColumn identifier] isEqualToString: @"Colour"]) {
481			NSColor* theColour = [[prefs colours] objectAtIndex: rowIndex];
482			NSAttributedString* res;
483
484			res = [[NSAttributedString alloc] initWithString: @"Sample"
485												  attributes: [NSDictionary dictionaryWithObjectsAndKeys:
486													  theColour, NSForegroundColorAttributeName,
487													  theColour, NSBackgroundColorAttributeName,
488													  nil]];
489
490			return [res autorelease];
491		}
492
493		return @" -- ";
494	}
495
496	return @" -- ";
497}
498
499// == Table delegate ==
500
501- (void)tableViewSelectionDidChange:(NSNotification *)aNotification {
502	if ([aNotification object] == fonts) {
503		int selFont = [fonts selectedRow];
504
505		if (selFont < 0) {
506			return;
507		}
508
509		NSFont* font = [[prefs fonts] objectAtIndex: selFont];
510
511		// Display font panel
512		[[NSFontPanel sharedFontPanel] setPanelFont: font
513										 isMultiple: NO];
514		[[NSFontPanel sharedFontPanel] setEnabled: YES];
515		[[NSFontPanel sharedFontPanel] setAccessoryView: nil];
516		[[NSFontPanel sharedFontPanel] orderFront: self];
517		[[NSFontPanel sharedFontPanel] reloadDefaultFontFamilies];
518	} else if ([aNotification object] == colours) {
519		int selColour = [colours selectedRow];
520
521		if (selColour < 0) {
522			return;
523		}
524
525		NSColor* colour = [[prefs colours] objectAtIndex: selColour];
526
527		// Display colours
528		[[NSColorPanel sharedColorPanel] setColor: colour];
529		[[NSColorPanel sharedColorPanel] setAccessoryView: nil];
530		[[NSColorPanel sharedColorPanel] orderFront: self];
531	}
532}
533
534// == Font panel delegate ==
535
536- (void) changeFont:(id) sender {
537	// Change the selected font in the font table
538	int selFont = [fonts selectedRow];
539
540	if (selFont < 0) return;
541
542	NSMutableArray* prefFonts = [[prefs fonts] mutableCopy];
543	NSFont* newFont;
544
545	newFont = [sender convertFont: [prefFonts objectAtIndex: selFont]];
546
547	if (newFont) {
548		[prefFonts replaceObjectAtIndex: selFont
549						 withObject: newFont];
550		[prefs setFonts: prefFonts];
551
552		[fonts reloadData];
553	}
554
555	[prefFonts release];
556
557	[self setSimpleFonts];
558}
559
560- (void)changeColor:(id)sender {
561	int selColour = [colours selectedRow];
562
563	if (selColour < 0) {
564		return;
565	}
566
567	NSColor* selected_colour = [[NSColorPanel sharedColorPanel] color];
568	NSColor* colour = [[selected_colour colorUsingColorSpaceName: NSCalibratedRGBColorSpace] colorWithAlphaComponent:(([transparencySlider floatValue] / 100.0))];
569
570	NSMutableArray* cols = [[prefs colours] mutableCopy];
571
572	if (colour) {
573		[cols replaceObjectAtIndex: selColour
574						withObject: colour];
575		[prefs setColours: cols];
576
577		[colours reloadData];
578		[self updateColourMenus];
579	}
580
581	[cols release];
582}
583
584- (void)changeTransparency:(id)sender {
585	NSMutableArray* cols = [[prefs colours] mutableCopy];
586
587	int i;
588	for(  i = 0; i < [cols count]; i++ )
589	{
590		NSColor * color = [cols objectAtIndex: i];
591
592		NSColor*  transparent_color = [[color colorUsingColorSpaceName: NSCalibratedRGBColorSpace] colorWithAlphaComponent:([transparencySlider floatValue] / 100.0)];
593
594		[cols replaceObjectAtIndex: i
595						withObject: transparent_color];
596	}
597
598	[prefs setColours: cols];
599
600	[colours reloadData];
601
602	[cols release];
603}
604
605// == Various actions ==
606
607- (IBAction) interpreterChanged: (id) sender {
608	[prefs setInterpreter: [interpreter indexOfSelectedItem]+1];
609}
610
611- (IBAction) glulxInterpreterChanged: (id) sender {
612	[prefs setGlulxInterpreter: [[glulxInterpreter selectedItem] tag]];
613}
614
615- (IBAction) revisionChanged: (id) sender {
616	[prefs setRevision: [[revision stringValue] characterAtIndex: 0]];
617}
618
619- (IBAction) displayWarningsChanged: (id) sender {
620	[prefs setDisplayWarnings: [sender state]==NSOnState];
621}
622
623- (IBAction) fatalWarningsChanged: (id) sender {
624	[prefs setFatalWarnings: [sender state]==NSOnState];
625}
626
627- (IBAction) speakGameTextChanged: (id) sender {
628	[prefs setSpeakGameText: [sender state]==NSOnState];
629}
630
631- (IBAction) scrollbackChanged: (id) sender {
632	[prefs setScrollbackLength: [sender floatValue]];
633}
634
635- (IBAction) autosaveChanged: (id) sender {
636	[prefs setAutosaveGames: [sender state]==NSOnState];
637}
638
639- (IBAction) confirmGameCloseChanged: (id) sender {
640	[prefs setConfirmGameClose: [sender state]==NSOnState];
641}
642
643- (IBAction) keepOrganisedChanged: (id) sender {
644	[prefs setKeepGamesOrganised: [sender state]==NSOnState];
645	[reorganiseGames setEnabled: [sender state]==NSOnState];
646	if ([sender state]==NSOffState) {
647		[autosaveGames setState: NSOffState];
648		[prefs setAutosaveGames: NO];
649	}
650}
651
652- (void) changeOrganiserDirTo: (NSOpenPanel *)sheet
653				   returnCode: (int)returnCode
654				  contextInfo: (void *)contextInfo {
655	if (returnCode != NSOKButton) return;
656
657	[[ZoomStoryOrganiser sharedStoryOrganiser] reorganiseStoriesTo: [sheet directory]];
658	[prefs setOrganiserDirectory: [sheet directory]];
659	[organiseDir setString: [prefs organiserDirectory]];
660}
661
662- (IBAction) changeOrganiseDir: (id) sender {
663	NSOpenPanel* dirChooser = [NSOpenPanel openPanel];
664
665	[dirChooser setAllowsMultipleSelection: NO];
666	[dirChooser setCanChooseDirectories: YES];
667	[dirChooser setCanChooseFiles: NO];
668	[dirChooser setCanCreateDirectories: YES];
669
670	NSString* path = [prefs organiserDirectory];
671
672	[dirChooser beginSheetForDirectory: path
673								  file: nil
674								 types: nil
675						modalForWindow: [self window]
676						 modalDelegate: self
677						didEndSelector: @selector(changeOrganiserDirTo:returnCode:contextInfo:)
678						   contextInfo: nil];
679}
680
681- (IBAction) resetOrganiseDir: (id) sender {
682	if ([prefs keepGamesOrganised]) {
683		[[ZoomStoryOrganiser sharedStoryOrganiser] reorganiseStoriesTo: [ZoomPreferences defaultOrganiserDirectory]];
684	}
685	[prefs setOrganiserDirectory: nil];
686	[organiseDir setString: [prefs organiserDirectory]];
687}
688
689
690- (IBAction) simpleFontsChanged: (id) sender {
691	// This action applies to all the font controls
692
693	// Set the size, if it has changed
694	float newSize = floorf([fontSizeSlider floatValue]);
695	if (newSize != [prefs fontSize]) [prefs setFontSize: newSize];
696
697	// Set the families, if they've changed
698	NSString* propFamily = [[proportionalFont selectedItem] title];
699	NSString* fixedFamily = [[fixedFont selectedItem] title];
700	NSString* symbolicFamily = [[symbolicFont selectedItem] title];
701
702	if (![propFamily isEqualToString: [prefs proportionalFontFamily]]) [prefs setProportionalFontFamily: propFamily];
703	if (![fixedFamily isEqualToString: [prefs fixedFontFamily]]) [prefs setFixedFontFamily: fixedFamily];
704	if (![symbolicFamily isEqualToString: [prefs symbolicFontFamily]]) [prefs setSymbolicFontFamily: symbolicFamily];
705
706	// Update the display
707	[self setSimpleFonts];
708}
709
710// = Typographical changes =
711
712- (IBAction) marginsChanged: (id) sender {
713	// Work out the new margin size
714	float oldSize = [prefs textMargin];
715	float newSize;
716
717	if ([showMargins state] == NSOffState) {
718		newSize = 0;
719		[marginWidth setEnabled: NO];
720	} else if ([showMargins state] == NSOnState && oldSize <= 0) {
721		newSize = 10.0;
722		[marginWidth setEnabled: YES];
723	} else {
724		newSize = floorf([marginWidth floatValue]);
725		[marginWidth setEnabled: YES];
726	}
727
728	if (newSize != oldSize) {
729		[prefs setTextMargin: newSize];
730	}
731}
732
733- (IBAction) screenFontsChanged: (id) sender {
734	BOOL newState = [useScreenFonts state]==NSOnState;
735
736	if (newState != [prefs useScreenFonts]) {
737		[prefs setUseScreenFonts: newState];
738	}
739}
740
741- (IBAction) hyphenationChanged: (id) sender {
742	BOOL newState = [useHyphenation state]==NSOnState;
743
744	if (newState != [prefs useHyphenation]) {
745		[prefs setUseHyphenation: newState];
746	}
747}
748
749- (IBAction) ligaturesChanged: (id) sender {
750	BOOL newState = [ligatures state]==NSOnState;
751
752	if (newState != [prefs useLigatures]) {
753		[prefs setUseLigatures: newState];
754	}
755}
756
757- (IBAction) kerningChanged: (id) sender {
758	BOOL newState = [kerning state]==NSOnState;
759
760	if (newState != [prefs useKerning]) {
761		[prefs setUseKerning: newState];
762	}
763}
764
765// = Story progress meter =
766
767- (void) storyProgressChanged: (NSNotification*) not {
768	NSDictionary* userInfo = [not userInfo];
769	BOOL activated = [[userInfo objectForKey: @"ActionStarting"] boolValue];
770
771	if (activated) {
772		indicatorCount++;
773	} else {
774		indicatorCount--;
775	}
776
777	if (indicatorCount <= 0) {
778		indicatorCount = 0;
779		[organiserIndicator stopAnimation: self];
780	} else {
781		[organiserIndicator startAnimation: self];
782	}
783}
784
785- (IBAction) reorganiseGames: (id) sender {
786	// Can't use this if keepGamesOrganised is off
787	if (![prefs keepGamesOrganised]) return;
788
789	// Reorganise all the stories
790	[[ZoomStoryOrganiser sharedStoryOrganiser] organiseAllStories];
791}
792
793// = Display pane =
794
795- (IBAction) bordersChanged: (id) sender {
796	BOOL newState = [sender state] == NSOnState;
797	BOOL oldState = [prefs showBorders];
798
799	if (newState != oldState) {
800		[prefs setShowBorders: newState];
801		[prefs setShowGlkBorders: newState];
802	}
803}
804
805- (IBAction) showCoverPictureChanged: (id) sender {
806	BOOL newState = [sender state] == NSOnState;
807	BOOL oldState = [prefs showCoverPicture];
808
809	if (newState != oldState) {
810		[prefs setShowCoverPicture: newState];
811	}
812}
813
814- (IBAction) colourChanged: (id) sender {
815	int newValue = [sender selectedTag];
816	int oldValue = (sender==foregroundColour)?[prefs foregroundColour]:[prefs backgroundColour];
817
818	if (newValue != oldValue) {
819		if (sender == foregroundColour) {
820			[prefs setForegroundColour: newValue];
821		} else {
822			[prefs setBackgroundColour: newValue];
823		}
824	}
825}
826
827@end
828