From 316004e79381f05dc1aedfd47eb07361e8553a20 Mon Sep 17 00:00:00 2001
From: Jeff Teunissen <deek@d2dc.net>
Date: Sun, 11 Nov 2001 20:54:59 +0000
Subject: [PATCH] Forge updates. Preferences seems to be debugged now.

---
 tools/Forge/.gitignore    |   3 +
 tools/Forge/Controller.m  | 135 ++++++++++---------
 tools/Forge/Forge.classes |  29 ++--
 tools/Forge/Forge.gorm    | Bin 10147 -> 10202 bytes
 tools/Forge/GNUmakefile   |   3 +
 tools/Forge/Preferences.h |  34 ++---
 tools/Forge/Preferences.m | 271 +++++++++++++++++++-------------------
 tools/Forge/main.m        |   3 +-
 8 files changed, 252 insertions(+), 226 deletions(-)

diff --git a/tools/Forge/.gitignore b/tools/Forge/.gitignore
index 2404c9420..078a6d52f 100644
--- a/tools/Forge/.gitignore
+++ b/tools/Forge/.gitignore
@@ -11,4 +11,7 @@ config.log
 config.status
 configure
 configure-stamp
+shared_debug_obj
 shared_obj
+shared_profile_debug_obj
+shared_profile_obj
diff --git a/tools/Forge/Controller.m b/tools/Forge/Controller.m
index 9576bf044..d0a4ece28 100644
--- a/tools/Forge/Controller.m
+++ b/tools/Forge/Controller.m
@@ -1,20 +1,35 @@
 /*
 	Controller.m
 
-	Central controller object for Edit...
+	Controller class for Forge
 
-	Copyright (c) 1995-1996, NeXT Software, Inc.
-	All rights reserved.
-	Author: Ali Ozer
+	Copyright (C) 2001 Jeff Teunissen <deek@quakeforge.net>
 
-	You may freely copy, distribute and reuse the code in this example.
-	NeXT disclaims any warranty of any kind, expressed or implied,
-	as to its fitness for any particular use.
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License as
+	published by the Free Software Foundation; either version 2 of
+	the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+	See the GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public
+	License along with this program; if not, write to:
+
+		Free Software Foundation, Inc.
+		59 Temple Place - Suite 330
+		Boston, MA  02111-1307, USA
+
+	$Id$
 */
 
 #import <AppKit/NSApplication.h>
 #import <AppKit/NSMenu.h>
 #import "Controller.h"
+#import "Preferences.h"
 
 @implementation Controller
 
@@ -81,7 +96,6 @@
 	NSLog (@"This _would_ save, but it doesn't.");
 }
 
-
 /*
 	Notifications
 */
@@ -112,31 +126,31 @@
 	NSMenu	*windows;
 	NSMenu	*services;
 
-	[menu addItemWithTitle: @"Info"		action: NULL	keyEquivalent: @""];
-	[menu addItemWithTitle: @"Project"	action: NULL	keyEquivalent: @""];
-	[menu addItemWithTitle: @"File"		action: NULL	keyEquivalent: @""];
-	[menu addItemWithTitle: @"Edit"		action: NULL	keyEquivalent: @""];
-	[menu addItemWithTitle: @"BSP"		action: NULL	keyEquivalent: @""];
-	[menu addItemWithTitle: @"Brush"	action: NULL	keyEquivalent: @""];
-	[menu addItemWithTitle: @"Windows"	action: NULL	keyEquivalent: @""];
-	[menu addItemWithTitle: @"Services"	action: NULL	keyEquivalent: @""];
+	[menu addItemWithTitle: _(@"Info")		action: NULL	keyEquivalent: @""];
+	[menu addItemWithTitle: _(@"Project")	action: NULL	keyEquivalent: @""];
+	[menu addItemWithTitle: _(@"File")		action: NULL	keyEquivalent: @""];
+	[menu addItemWithTitle: _(@"Edit")		action: NULL	keyEquivalent: @""];
+	[menu addItemWithTitle: _(@"BSP")		action: NULL	keyEquivalent: @""];
+	[menu addItemWithTitle: _(@"Brush")		action: NULL	keyEquivalent: @""];
+	[menu addItemWithTitle: _(@"Windows")	action: NULL	keyEquivalent: @""];
+	[menu addItemWithTitle: _(@"Services")	action: NULL	keyEquivalent: @""];
 
-	[menu addItemWithTitle: @"Hide"		action: @selector(hide:)	keyEquivalent: @"h"];
-	[menu addItemWithTitle: @"Quit"		action: @selector(terminate:)	keyEquivalent: @"q"];
+	[menu addItemWithTitle: _(@"Hide")		action: @selector(hide:)	keyEquivalent: @"h"];
+	[menu addItemWithTitle: _(@"Quit")		action: @selector(terminate:)	keyEquivalent: @"q"];
 
 	/*
 		Info
 	*/
 	info = [[[NSMenu alloc] init] autorelease];
-	[menu setSubmenu: info	forItem: [menu itemWithTitle: @"Info"]];
+	[menu setSubmenu: info	forItem: [menu itemWithTitle: _(@"Info")]];
 
-	[info addItemWithTitle: @"Info Panel..."
+	[info addItemWithTitle: _(@"Info Panel...")
 					action: @selector (orderFrontStandardAboutPanel:)
 			 keyEquivalent: @""];
-	[info addItemWithTitle: @"Preferences..."
+	[info addItemWithTitle: _(@"Preferences...")
 					action: @selector (orderFrontPreferencesPanel:)
 			 keyEquivalent: @""];
-	[info addItemWithTitle: @"Help"
+	[info addItemWithTitle: _(@"Help")
 					action: @selector (orderFrontHelpPanel:)
 			 keyEquivalent: @"?"];
 
@@ -144,21 +158,21 @@
 		Project
 	*/
 	project = [[[NSMenu alloc] init] autorelease];
-	[menu setSubmenu: project	forItem: [menu itemWithTitle: @"Project"]];
+	[menu setSubmenu: project	forItem: [menu itemWithTitle: _(@"Project")]];
 
-	[project addItemWithTitle: @"Open..."
+	[project addItemWithTitle: _(@"Open...")
 					   action: @selector (openProject:)
-				keyEquivalent: @"@o"];
-	[project addItemWithTitle: @"New"
+				keyEquivalent: @"~o"];
+	[project addItemWithTitle: _(@"New")
 					   action: @selector (createNewProject:)
-				keyEquivalent: @"@n"];
-	[project addItemWithTitle: @"Save..."
+				keyEquivalent: @"~n"];
+	[project addItemWithTitle: _(@"Save...")
 					   action: @selector (saveProject:)
-				keyEquivalent: @"@s"];
-	[project addItemWithTitle: @"Save As..."
+				keyEquivalent: @"~s"];
+	[project addItemWithTitle: _(@"Save As...")
 					   action: @selector (saveProjectAs:)
-				keyEquivalent: @"@S"];
-	[project addItemWithTitle: @"Close"
+				keyEquivalent: @"~S"];
+	[project addItemWithTitle: _(@"Close")
 					   action: @selector (closeProject:)
 				keyEquivalent: @""];
 
@@ -166,27 +180,27 @@
 		File
 	*/
 	file = [[[NSMenu alloc] init] autorelease];
-	[menu setSubmenu: file	forItem: [menu itemWithTitle: @"File"]];
+	[menu setSubmenu: file	forItem: [menu itemWithTitle: _(@"File")]];
 
-	[file addItemWithTitle: @"Open..."
+	[file addItemWithTitle: _(@"Open...")
 					action: @selector (open:)
 			 keyEquivalent: @"o"];
-	[file addItemWithTitle: @"New"
+	[file addItemWithTitle: _(@"New")
 					action: @selector (createNew:)
 			 keyEquivalent: @"n"];
-	[file addItemWithTitle: @"Save..."
+	[file addItemWithTitle: _(@"Save...")
 					action: @selector (save:)
 			 keyEquivalent: @"s"];
-	[file addItemWithTitle: @"Save As..."
+	[file addItemWithTitle: _(@"Save As...")
 					action: @selector (saveAs:)
 			 keyEquivalent: @"S"];
-	[file addItemWithTitle: @"Save All"
+	[file addItemWithTitle: _(@"Save All")
 					action: @selector (saveAll:)
 			 keyEquivalent: @""];
-	[file addItemWithTitle: @"Revert to Saved"
+	[file addItemWithTitle: _(@"Revert to Saved")
 					action: @selector (revertToSaved:)
 			 keyEquivalent: @""];
-	[file addItemWithTitle: @"Close"
+	[file addItemWithTitle: _(@"Close")
 					action: @selector (close:)
 			 keyEquivalent: @""];
 
@@ -194,58 +208,61 @@
 		Edit
 	*/
 	edit = [[[NSMenu alloc] init] autorelease];
-	[menu setSubmenu: edit forItem: [menu itemWithTitle: @"Edit"]];
+	[menu setSubmenu: edit forItem: [menu itemWithTitle: _(@"Edit")]];
 	
-	[edit addItemWithTitle: @"Undo"
+	[edit addItemWithTitle: _(@"Undo")
 					action: @selector (undo:)
 			 keyEquivalent: @"z"];
-	[edit addItemWithTitle: @"Redo"
+	[edit addItemWithTitle: _(@"Redo")
 					action: @selector (redo:)
 			 keyEquivalent: @"Z"];
-	[edit addItemWithTitle: @"Cut"
+	[edit addItemWithTitle: _(@"Cut")
 					action: @selector (cut:)
 			 keyEquivalent: @"x"];
-	[edit addItemWithTitle: @"Copy"
+	[edit addItemWithTitle: _(@"Copy")
 					action: @selector (copy:)
 			 keyEquivalent: @"c"];
-	[edit addItemWithTitle: @"Paste"
+	[edit addItemWithTitle: _(@"Paste")
 					action: @selector (paste:)
 			 keyEquivalent: @"v"];
+	[edit addItemWithTitle: _(@"Delete")
+					action: @selector (delete:)
+			 keyEquivalent: @""];
+	[edit addItemWithTitle: _(@"Select All")
+					action: @selector (selectAll:)
+			 keyEquivalent: @"a"];
 
 	/*
 		BSP
 	*/
 	bsp = [[[NSMenu alloc] init] autorelease];
-	[menu setSubmenu: bsp forItem: [menu itemWithTitle: @"BSP"]];
+	[menu setSubmenu: bsp forItem: [menu itemWithTitle: _(@"BSP")]];
 	
-	[bsp addItemWithTitle: @"dunno"
-					action: @selector (undo:)
-			 keyEquivalent: @"z"];
+	[bsp addItemWithTitle: _(@"None")	action: @selector(nothing:)	keyEquivalent: @""];
+
 	/*
 		Brush
 	*/
 	brush = [[[NSMenu alloc] init] autorelease];
-	[menu setSubmenu: brush forItem: [menu itemWithTitle: @"Brush"]];
+	[menu setSubmenu: brush forItem: [menu itemWithTitle: _(@"Brush")]];
 	
-	[brush addItemWithTitle: @"dunno"
-					action: @selector (undo:)
-			 keyEquivalent: @"z"];
+	[brush addItemWithTitle: _(@"none")	action: @selector(nothing:)	keyEquivalent: @""];
 
 	/*
 		Windows
 	*/
 	windows = [[[NSMenu alloc] init] autorelease];
-	
-	[menu setSubmenu: windows	forItem: [menu itemWithTitle: @"Windows"]];
-	
+
 	[NSApp setWindowsMenu: windows];
+	[menu setSubmenu: windows	forItem: [menu itemWithTitle: _(@"Windows")]];
 
 	/*
 		Services
 	*/
 	services = [[[NSMenu alloc] init] autorelease];
+
 	[NSApp setServicesMenu: services];
-	[menu setSubmenu: services	forItem: [menu itemWithTitle: @"Services"]];
+	[menu setSubmenu: services	forItem: [menu itemWithTitle: _(@"Services")]];
 
 	[NSApp setMainMenu: menu];
 }
@@ -253,7 +270,7 @@
 /*
 	applicationWillTerminate:
 
-	Sort of like SIGQUIT. App should die now, but has a chance to clean up
+	Sort of like SIGQUIT. App is about to die, but has a chance to clean up
 */
 - (void) applicationWillTerminate: (NSNotification *) not;
 {
diff --git a/tools/Forge/Forge.classes b/tools/Forge/Forge.classes
index 39617bde8..c35c0a8cd 100644
--- a/tools/Forge/Forge.classes
+++ b/tools/Forge/Forge.classes
@@ -11,6 +11,17 @@
 	);
 	Super = NSObject;
     };
+    IBInspector = {
+	Actions = (
+	    ok:,
+	    revert:,
+	    touch:
+	);
+	Outlets = (
+	    window
+	);
+	Super = NSObject;
+    };
     NSApplication = {
 	Outlets = (
 	    delegate
@@ -73,15 +84,15 @@
 	    revert:
 	);
 	Outlets = (
-	    bspSoundPathField,
-	    offsetBrushCopyButton,
-	    projectPathField,
-	    showBSPOutputButton,
-	    startWadField,
-	    xLightField,
-	    yLightField,
-	    zLightField
+	    bspSoundPath,
+	    offsetBrushCopy,
+	    projectPath,
+	    showBSPOutput,
+	    startWad,
+	    xLight,
+	    yLight,
+	    zLight
 	);
 	Super = NSObject;
     };
-}
\ No newline at end of file
+}
diff --git a/tools/Forge/Forge.gorm b/tools/Forge/Forge.gorm
index 657fecbd9d61b02e583c452153d8c9f7a2c671e6..32d678d2ee395510e3a59c7ca957c099e15168f3 100644
GIT binary patch
literal 10202
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
E4-|b}cmMzZ

literal 10147
zcmcgy3w#_!8K2u+9+%6jX`51{aw?!uY`?wqm8kTROH-ocL9akj9^G8F$<fR1v3HlW
zh!U-W4}>#55JUx0M2fNpKJbAS6$KSUQ9w~CqN3sh#rF%pZ{~J0cbiMLK)w9Botyb)
z=KuZY`@Z>RZnqAdmd)vzh-M`xQd2tMC%RFMc2faB)kHxB-Kpv9hJYGiEn5>qsnNJ;
z<g}EbTMR#{!WxDW!=vZv$sB!Wpr|!$=}=-YpVLOudS5D;OPPjd?WIOF$eM-{<#p^h
zY&a2W)LI%Tk+V|9IMxJsef_amtX+<edIhJM##td)tfel^Zc{Th^<*;XR8ph4pjHSp
zx&n;~VYbY48oSr2bu7dc8OZ6AI1poYZAV9#3j84zq24>xAnJZb$`~`Jp+T)D%;Fn%
zSJVa;9!hM}vl-JE;{*j5p<spb3HrKluD%U1u45~g=m^J0s4^2{5K=>|ZYXhjN}tBQ
ziwsd^WQFm+08!OmC_tmy$XeWG>9H(LtVo#EBYUN<g7gsa9fGjh#A=5Uz2=^B5b+0Q
z5a;R`L&yj{+zX7AgK(=$Ah?<#1kqG%Bs>9{AOOw9kV{VNAdW;29CQU1d%S}>)v{&`
z2W=69GH6wsS?f?@yS^vapVHG~aXp=;iPRRdx*l$bZe1%e?0jR;CKkGm0C9V(Q{vjB
zZfONrqPCH2KbjCWqJ_5$*;-e&R_U=)TAH+~3-`oGNPOgS!6BpC|HO>K>7fVbY`%w5
zC=>*3vvwGks!M1A<7V0<f2?7!OrTroqFagX5!ceGQA^9|W81d&a^XZqOX}gxCmh%(
zJ!oFx2%=#IwOw9ZVlSKXj(JO)QBVnVgk#sxD&m7Cuc3zm9mOUpa2JSQhwXi<$aH$|
z!XiD&O~<X~ECm$TbXJs^&JnWdJer&-nNIKi`wQXTi#>xn)s?2R(lMPQi_P#nL7YNp
zxd|xBjx!7PlEblZ9rjW<>QIQimUO(PjM!B&vD_ykM6Bz4<;1$xj`@+1kxxFqjM$@P
zVh_@4;^WYLGU5>X0wnf@|3_k1A+awy6k?InN@9<ZiRBjCPQ(h+^u#5%x{}yq%ZNR0
zeqwuX!uh?y&aJMr*cUs*z66OqUJ%>hT5N-|#mJ>{DLs3b?DiO>_k?Fj?`jXd_0NRf
z6U*p*>2pKx8i(GsNG}L_<s78f%4a7I8@sEKUG-VA8<pARQGv4?zj9{2aO+lA8gFMA
zyX)p>H$F>)dcv(+U1_}Q9d<V$yBh_&@{YSrAIJRdFqv)?$=&oU$?a0xDZz6y3=E+G
zbtwzc2Fw#os+i08_;we6ng`H($j=|bqLf}@Ty?5ts#aoD?k-V9uFc?O$k)pSUoEb)
zw_sK~IjI?Ak>PwUlh0M<4R=w6{^6gSS@68D>Q_0(=z>>p)@Y9p&pilNDOGS9;3U8F
zB9g)^Y%aEQ^(Z+OR6R9AdkyF0hWV+&YMH9zk*Zi3RXs>mub@gkAvjbG80AcrcyY$W
z|DQQin<4I(sXo6<AsS?Ai@J;s8iN|1jw-V8zK#Q!QXS2Sqb2Fhc!+bV9VMNezrT#Q
zt;H5NSrEsnnvz5Q0;V))RJ<ga5++i#-ikvqE;T{xx$4IK9dnii1A@dwGgEtj6oOX@
z%sk2DX<HNKyS@2b&NL{!hgYe~DgB?T!8rpAP7&SYL*kAzBWcszozFyIQ0<_!dSFr;
z*SWkBfFaSN&2_*wC5aAb8s{daQ@P~C@UC4xlSNJp_rRKJ4k^<H!_Kn6NT~#;7CR8q
zHu068Ai3_X6_5<!@@+H?pD;k^d1fAfgjoL?I=9ro_Tq9lO^g?IRSYXT*1D|NgF?S@
zpOH+0)?;oaDpk=h$Rz#jE%tB$PA_R@pXz}OXCSm4UTBF4b2<_?O=~Rs+(AS8EFG`{
zg;@^G9+?l*nTYAt0@M69bT}X>3qdLrW@l%WKmqr;*9c(p-deh{I7_t1XV-qy8rSW!
zI>LQjGZ;!vieU`yKPtxfgDgR;Z~!AC{n57ohTXHhbBOq4Z-H|pVj9W38iQ;*)7c)D
zWBn|Jr8FC3o%Uup*Oz3}?t+~{GDwK{n86_HWhRcf-j0G+wRN4n8b+(OcG|~4vTAG8
zUIk-STUEOQbkWK^ihE#<f)^%uFyAE_xNTIYK!tH>6O7py4*Q}9XcN2~*P>^qCzd<a
zd>L>dc>KWCm?(?oDcl6l69D9u-k!>(^#bfJwn5t4D&Jw?#LkC6IG<;H6s|}&92djA
z%^rtI5%6bF`GxZfg9{Rvd2b<j1C2oB;I3&39r+~_Uz?EPW^Ry?c|S<Juii<#Uq-xp
zlMko5lK1n=c(;)EteAC~8$*{VYfmwgT6*m%bOmGWUCSL#+G5M&DSa!|@Wpil>fFY<
z0Gk=e`DHVIXlzaiy~+%F5Ixyoc{YH4t+PoMWnD0>u3(LrtLR3)bis<d?H<ut-l&E%
zx)I4(CfyvbS+fTA3K70R@zn|_!=yXkyPht^p#ogMH@?>jVV*y7;dW=^i}uAQ^yKbA
z&Dvdn3%T&?gs_|rmNxEaU!RtpAY<X<qaVFq$S$JgCb+1$0%nA)oO#64W>$}sV(lA5
zyR6Z4rA8R8FDTd-B7|swHM3Agw|1G<Bp;`HN{z;#dtGdkgYJ#K&~1c$i0(~7R;Fk$
zWu&xR-b!8IVtlg~<KzMu6^5ss5=Ln>FVc&BA>9C%Akw!8Svj$y3u$9qj|>=*ehZIQ
z@KzzieL%JdiN6}w%0imxIAHK@UR-bUg=;;$9dTVMWaaa}SlKMRV{te^*1|&B{OBY)
zg1CFGL<5(pN6^hOxe6M3fZ3PA<#JADUt;gGFTy;p;0yIScqgKs6|(ZBP(rt+Qb|1v
z?^+yoEy8Byu!Z%(yNgHIv+$l$z(Z8;^@XYvu0T}p6S92w<_;TFC_2EERS@A3q~sT_
zYhLARx+uIKr@LCn%9|g*x`7W=nQzXHZsDC+0X~TOUJV}-`ih?{>?=_1Ykc8Q;abG;
zVIk{L`?@MH=2812zNQ2CC{B01kS)tb5+m@jDznX_^bM%=_3-gBrLRS$Z}fpe#pu5u
zQQRbCWxqLDPiH8|e?m0LA#rnMxS5B8Px_jD6Wolm+d@{pCmFHyUAm<k=mG?yC?q_w
zWS)s{@ip;AxD_Y<l#rFTnE_*$85z+GJx%j|y2`wB%Mh(&jVzSHUc6Ixta1bRj4wPJ
z;IoM5HX&PPdpI(DZc!Mn3w$1};Wqd}SxmaszS-W77V$-2P}alk2<1zXEcgCKC84Kr
z<B#;<3H{5WRW=H(x=}>yiK8s<j=d{`Y5@*NlR24pWul_8b#Mm)`-+g2<HU%Dzm3CJ
zy_lvdF-hyz!0<=q4E6M`+1GsG>4ZBG&)0>lyk>DTvlqVMg_B$WPKedAP!c<O(cI+=
zO%(1%G~X1mayW_SbMP%Mm^}-CX=FhJlh1jveA^cm74AVS_X=5=nJr_f9DGOAdz^W0
zaa?P@53TuL_^z<#ARSAC_TBcK_8s=^XwTpC1qR@L1oM3%E1M0^*x(0?qKSsdRFae@
zdI@<zbmu1)Zn~i$t2Es%cn}dhBqZg8+R~?VD;L>rMiSbTJ_bLmf@LnuMVlx`5&gEC
zyq6c#k9=U-1P>#o9}CH{%ma~dAOA@eFmuZkZDtMV*Vuu)+7tPH>I23Gcm!b_6q53-
z45=3B;lck=(JBX<!~(|K!s<()vR+I-^MPqSJcgKlE+pkGkucG&@Cz@X>;iyV$+d|k
zFPvZcfU^!BM>xL{lConD>C^CQFBGE^iex=)=-ABAr@Niw$!~lB=!7Q_z;A`5%m<wZ
ziI3lTL70^wB&%6Me3;nR%g671z=^^i5YCfAQnuVaGnvQKJqLdjZGHmGpD@5Y2~UXt
z(?9{H!G6M?wjZ}2vmdb^wjZ?b$3XLEAFx#T3&Q%Vkd$NIsd<cfe-rhx4WGXNMeVd<
z=5%W^W#Ahi-VO8bVmMiQ=kyN$Kp6k@!Z<lKro+FyFeVm&v6NP70y}yU{9BA9-_+3S
zPuUc{K?eU3d@}g2C^QkVP4Kk3l3r*MFQgfmOYj$9@MW(0kpL6p$>vphd#o@L2ozV^
zx?PVY1xsVRRD-1?F9oqQ%1gCa(s-#3OFMa~9!ux)QUjLG;iV9k&gP{?EY;o@U^sMG
kJ(4Zs=<vt6w4TG?2PKRsW7m!ZngmRl_%Y0D#&MPY2Z$P01poj5

diff --git a/tools/Forge/GNUmakefile b/tools/Forge/GNUmakefile
index 9ea4ca258..822034f68 100644
--- a/tools/Forge/GNUmakefile
+++ b/tools/Forge/GNUmakefile
@@ -53,6 +53,9 @@ Forge_RESOURCE_FILES= \
 	Forge.tiff \
 	ForgeInfo.plist
 
+Forge_LOCALIZED_RESOURCE_FILES= \
+	Localizable.strings
+
 # Languages we're localized for
 Forge_LANGUAGES= \
 	English
diff --git a/tools/Forge/Preferences.h b/tools/Forge/Preferences.h
index afccb9a1c..1adb160d1 100644
--- a/tools/Forge/Preferences.h
+++ b/tools/Forge/Preferences.h
@@ -47,24 +47,21 @@
 @interface Preferences: NSObject
 {
 	// UI targets
-	id		projectPathField;		// path to the project to load on startup
-	id		bspSoundPathField;		// location of BSP sounds
-	id		startWadField;			// which wadfile to load on startup
-	id		xLightField;			// Lighting for X side
-	id		yLightField;			// Lighting for Y side
-	id		zLightField;			// Lighting for Z side
-	id		showBSPOutputButton; 	// "Show BSP Output" checkbox
-	id		offsetBrushCopyButton;	// "Brush offset" checkbox
-
-	NSDictionary		*currentValues;
-	NSMutableDictionary *displayedValues;
+	NSString	*projectPath;		// path to the project to load on startup
+	NSString	*bspSoundPath;		// location of BSP sounds
+	NSString	*startWad;			// which wadfile to load on startup
+	float		xLight;				// Lighting for X side
+	float		yLight;				// Lighting for Y side
+	float		zLight;				// Lighting for Z side
+	BOOL		showBSPOutput;		// "Show BSP Output" checkbox
+	BOOL		offsetBrushCopy;	// "Brush offset" checkbox
 }
 
-+ (void) saveDefaults;
-- (void) loadDefaults;
-
 + (Preferences *) sharedInstance;	// Return the shared instance
 
+- (void) saveDefaults;
+- (void) loadDefaults;
+
 - (NSDictionary *) preferences; 	// current prefs
 
 - (void) updateUI;					// Update the displayed values in the UI
@@ -81,12 +78,9 @@
 
 
 - (id) objectForKey: (id) key;
-//+ (void) setObject: (id) obj forKey: (id) key;
+- (void) setObject: (id) obj forKey: (id) key;
 
-
-+ (NSDictionary *) preferencesFromDefaults;
-+ (void) savePreferencesToDefaults: (NSDictionary *) dict;
+- (NSDictionary *) preferencesFromDefaults;
+- (void) savePreferencesToDefaults: (NSDictionary *) dict;
 
 @end
-
-extern Preferences	*prefs;
diff --git a/tools/Forge/Preferences.m b/tools/Forge/Preferences.m
index eb958503f..3fe1ca42a 100644
--- a/tools/Forge/Preferences.m
+++ b/tools/Forge/Preferences.m
@@ -36,15 +36,15 @@
 
 #import "Preferences.h"
 
-id	prefs;
+NSMutableDictionary *
+defaultValues (void) {
+    static NSMutableDictionary *dict = nil;
 
-static NSDictionary *defaultValues (void) {
-    static NSDictionary *dict = nil;
     if (!dict) {
-        dict = [[NSDictionary alloc] initWithObjectsAndKeys:
+        dict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
 				@"/Local/Forge/Projects", ProjectPath,
-				@"/Local/Forge/Sounds", BspSoundPath,
-				[NSNumber numberWithInt: 0], StartWad,
+				@"/Local/Library/Sounds", BspSoundPath,
+				@"none", StartWad,
 				[NSNumber numberWithFloat: 1.0], XLight,
 				[NSNumber numberWithFloat: 0.6], YLight,
 				[NSNumber numberWithFloat: 0.75], ZLight,
@@ -55,25 +55,95 @@ static NSDictionary *defaultValues (void) {
     return dict;
 }
 
+/***
+	Code to deal with defaults
+***/
+BOOL
+getBoolDefault (NSMutableDictionary *dict, NSString *name)
+{
+	NSString	*str = [[NSUserDefaults standardUserDefaults] stringForKey: name];
+	NSNumber	*num;
+
+	if (!str)
+		str = [[defaultValues() objectForKey: name] stringValue];
+
+	num = [NSNumber numberWithBool: [str hasPrefix: @"Y"]];
+	[dict setObject: num forKey: name];
+
+	return [num boolValue];
+}
+
+float
+getFloatDefault (NSMutableDictionary *dict, NSString *name)
+{
+	NSString	*str = [[NSUserDefaults standardUserDefaults] stringForKey: name];
+	NSNumber	*num;
+
+	if (!str)
+		str = [[defaultValues() objectForKey: name] stringValue];
+
+	num = [NSNumber numberWithFloat: [str floatValue]];
+	[dict setObject: num forKey: name];
+	
+	return [num floatValue];
+}
+
+int
+getIntDefault (NSMutableDictionary *dict, NSString *name)
+{
+	NSString	*str = [[NSUserDefaults standardUserDefaults] stringForKey: name];
+	NSNumber	*num;
+
+	if (!str)
+		str = [[defaultValues() objectForKey: name] stringValue];
+
+	num = [NSNumber numberWithInt: [str intValue]];
+	[dict setObject: num forKey: name];
+	
+	return [num intValue];
+}
+
+NSString *
+getStringDefault (NSMutableDictionary *dict, NSString *name)
+{
+	NSString	*str = [[NSUserDefaults standardUserDefaults] stringForKey: name];
+
+	if (!str)
+		str = [defaultValues() objectForKey: name];
+
+	[dict setObject: str forKey: name];
+	
+	return str;
+}
+
 @implementation Preferences
 
-static Preferences	*sharedInstance = nil;
+static Preferences			*sharedInstance = nil;
+static NSDictionary			*currentValues = nil;
+static NSMutableDictionary	*displayedValues = nil;
 
 - (id) objectForKey: (id) key
 {
-    return [[[[self class] sharedInstance] preferences] objectForKey: key];
+	id		obj = [[NSUserDefaults standardUserDefaults] objectForKey: key];
+	
+	if (!obj)
+		return [defaultValues () objectForKey: key];
+	else
+		return obj;
 }
 
-+ (void) saveDefaults
+- (void) setObject: (id) obj forKey: (id) key
 {
-	if (sharedInstance) {
-		[self savePreferencesToDefaults: [sharedInstance preferences]];
-	}
+	if ((!key) || (!obj))
+		return;
+
+	[displayedValues setObject: obj forKey: key];
+	[self commitDisplayedValues];
 }
 
-- (void) saveDefaults: (id) sender
+- (void) saveDefaults
 {
-	[[self class] saveDefaults];
+	[self savePreferencesToDefaults: currentValues];
 }
 
 - (void) loadDefaults
@@ -81,7 +151,7 @@ static Preferences	*sharedInstance = nil;
 	if (currentValues)
 		[currentValues release];
 
-	currentValues = [[[self class] preferencesFromDefaults] copyWithZone: [self zone]];
+	currentValues = [[self preferencesFromDefaults] copyWithZone: [self zone]];
 	[self discardDisplayedValues];
 }
 
@@ -96,16 +166,16 @@ static Preferences	*sharedInstance = nil;
 		[self dealloc];
 	} else {
 		[super init];
-		currentValues = [[[self class] preferencesFromDefaults] copyWithZone:[self zone]];
+		currentValues = [[self preferencesFromDefaults] mutableCopy];
 		[self discardDisplayedValues];
 		sharedInstance = self;
-		prefs = sharedInstance;
 		[[NSNotificationCenter defaultCenter]
 			addObserver: self
-			selector: @selector(saveDefaults:)
+			selector: @selector(saveDefaults)
 			name: @"NSApplicationWillTerminateNotification"
 			object: nil];
 	}
+	[self prefsChanged: self];
 	return sharedInstance;
 }
 
@@ -130,87 +200,54 @@ static Preferences	*sharedInstance = nil;
 */
 - (void) updateUI
 {
-	id theCenter = [NSNotificationCenter defaultCenter];
-
-	NSLog (@"Defaults updated, UI should update.");
-
-	[theCenter postNotificationName: @"ForgeTextureCacheShouldFlush" object: self userInfo: nil];
-	[theCenter postNotificationName: @"ForgeUIShouldUpdate" object: self userInfo: nil];
-
 	return;
 }
 
-- (void) prefsChanged: (id) sender {
-	static NSNumber 	*yes = nil;
-	static NSNumber 	*no = nil;
-	int 				anInt;
+- (void) prefsChanged: (id) sender
+{
 	float				aFloat;
-	
-	if (!yes) {
-		yes = [[NSNumber alloc] initWithBool: YES];
-		no = [[NSNumber alloc] initWithBool: NO];
+
+	[displayedValues setObject: projectPath forKey: ProjectPath];
+	[displayedValues setObject: bspSoundPath forKey: BspSoundPath];
+	[displayedValues setObject: startWad forKey: StartWad];
+
+	if ((aFloat = [[displayedValues objectForKey: XLight] floatValue]) < 0.0 || aFloat > 1.0) {
+		aFloat = [[defaultValues () objectForKey: XLight] floatValue];
 	}
+	xLight = aFloat;
+	[displayedValues setObject: [NSNumber numberWithFloat: xLight] forKey: XLight];
 
-	[displayedValues setObject: [projectPathField stringValue] forKey: ProjectPath];
-	[displayedValues setObject: [bspSoundPathField stringValue] forKey: BspSoundPath];
-
-	if ((anInt = [startWadField intValue]) < 0 || anInt > 2) {
-		if ((anInt = [[displayedValues objectForKey: StartWad] intValue]) < 0 || anInt > 2) {
-			anInt = [[defaultValues () objectForKey: StartWad] intValue];
-		}
-		[startWadField setIntValue: anInt];
-	} else {
-		[displayedValues setObject: [NSNumber numberWithInt: anInt] forKey: StartWad];
+	if ((aFloat = [[displayedValues objectForKey: YLight] floatValue]) < 0.0 || aFloat > 1.0) {
+		aFloat = [[defaultValues () objectForKey: YLight] floatValue];
 	}
+	yLight = aFloat;
+	[displayedValues setObject: [NSNumber numberWithFloat: yLight] forKey: YLight];
 
-	if ((aFloat = [xLightField floatValue]) < 0.0 || aFloat > 1.0) {
-		if ((aFloat = [[displayedValues objectForKey: XLight] floatValue]) < 0.0 || aFloat > 1.0) {
-			aFloat = [[defaultValues () objectForKey: XLight] floatValue];
-		}
-		[xLightField setFloatValue: aFloat];
-	} else {
-		[displayedValues setObject: [NSNumber numberWithFloat: aFloat] forKey: XLight];
+	if ((aFloat = [[displayedValues objectForKey: ZLight] floatValue]) < 0.0 || aFloat > 1.0) {
+		aFloat = [[defaultValues () objectForKey: ZLight] floatValue];
 	}
+	zLight = aFloat;
+	[displayedValues setObject: [NSNumber numberWithFloat: zLight] forKey: ZLight];
 
-	if ((aFloat = [yLightField floatValue]) < 0.0 || aFloat > 1.0) {
-		if ((aFloat = [[displayedValues objectForKey: YLight] floatValue]) < 0.0 || aFloat > 1.0) {
-			aFloat = [[defaultValues () objectForKey: YLight] floatValue];
-		}
-		[yLightField setFloatValue: aFloat];
-	} else {
-		[displayedValues setObject: [NSNumber numberWithFloat: aFloat] forKey: YLight];
-	}
-
-	if ((aFloat = [zLightField floatValue]) < 0.0 || aFloat > 1.0) {
-		if ((aFloat = [[displayedValues objectForKey: YLight] floatValue]) < 0.0 || aFloat > 1.0) {
-			aFloat = [[defaultValues () objectForKey: YLight] floatValue];
-		}
-		[zLightField setFloatValue: aFloat];
-	} else {
-		[displayedValues setObject: [NSNumber numberWithFloat: aFloat] forKey: ZLight];
-	}
-
-	[displayedValues setObject: ([showBSPOutputButton state] ? yes : no) forKey: ShowBSPOutput];
-	[displayedValues setObject: ([offsetBrushCopyButton state] ? yes : no) forKey: OffsetBrushCopy];
+	[displayedValues setObject: [NSNumber numberWithBool: showBSPOutput] forKey: ShowBSPOutput];
+	[displayedValues setObject: [NSNumber numberWithBool: offsetBrushCopy] forKey: OffsetBrushCopy];
 
 	[self commitDisplayedValues];
 }
 
 - (void) commitDisplayedValues
 {
-	if (currentValues != displayedValues) {
-		[currentValues release];
-		currentValues = [displayedValues copyWithZone: [self zone]];
-	}
+	[currentValues release];
+	currentValues = [[displayedValues copy] retain];
+	[self saveDefaults];
+	[self updateUI];
 }
 
 - (void) discardDisplayedValues
 {
-	if (currentValues != displayedValues) {
-		[displayedValues release];
-		displayedValues = [currentValues mutableCopyWithZone: [self zone]];
-		[self updateUI];
-	}
+	[displayedValues release];
+	displayedValues = [[currentValues mutableCopy] retain];
+	[self updateUI];
 }
 
 - (void) ok: (id) sender
@@ -228,101 +265,61 @@ static Preferences	*sharedInstance = nil;
 	if (currentValues)
 		[currentValues release];
 
-	currentValues = [defaultValues () copyWithZone: [self zone]];
-	[currentValues retain];
+	currentValues = defaultValues ();
 
 	[self discardDisplayedValues];
 }
 
-/***
-	Code to deal with defaults
-***/
-
-#define getBoolDefault(name) \
-{ \
-	NSString *str = [defaults stringForKey: name]; \
-	[dict setObject: (str ? [NSNumber numberWithBool: [str hasPrefix: @"Y"]] : [defaultValues() objectForKey: name]) forKey: name]; \
-}
-
-#define getFloatDefault(name) \
-{ \
-	NSString *str = [defaults stringForKey: name]; \
-	[dict setObject: (str ? [NSNumber numberWithFloat: [str floatValue]] : [defaultValues() objectForKey: name]) forKey: name]; \
-}
-
-#define getIntDefault(name) \
-{ \
-	NSString *str = [defaults stringForKey: name]; \
-	[dict setObject: (str ? [NSNumber numberWithInt: [str intValue]] : [defaultValues() objectForKey: name]) forKey: name]; \
-}
-
-#define getStringDefault(name) \
-{ \
-	NSString *str = [defaults stringForKey: name]; \
-	[dict setObject: (str ? str : [defaultValues() objectForKey: name]) forKey: name]; \
-}
-
-+ (NSDictionary *) preferencesFromDefaults
+- (NSDictionary *) preferencesFromDefaults
 {
-	NSUserDefaults		*defaults = [NSUserDefaults standardUserDefaults];
 	NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity: 10];
 
-	getStringDefault(ProjectPath);
-	getStringDefault(BspSoundPath);
-	getIntDefault(StartWad);
-	getFloatDefault(XLight);
-	getFloatDefault(YLight);
-	getFloatDefault(ZLight);
-	getBoolDefault(ShowBSPOutput);
-	getBoolDefault(OffsetBrushCopy);
+	projectPath = getStringDefault (dict, ProjectPath);
+	bspSoundPath = getStringDefault (dict, BspSoundPath);
+	startWad = getStringDefault (dict, StartWad);
+	xLight = getFloatDefault (dict, XLight);
+	yLight = getFloatDefault (dict, YLight);
+	zLight = getFloatDefault (dict, ZLight);
+	showBSPOutput = getBoolDefault (dict, ShowBSPOutput);
+	offsetBrushCopy = getBoolDefault (dict, OffsetBrushCopy);
 
 	return dict;
 }
 
 #define setBoolDefault(name) \
 { \
-	if ([[defaultValues() objectForKey: name] isEqual: [dict objectForKey: name]]) \
-		[defaults removeObjectForKey: name]; \
-	else \
-		[defaults setBool:[[dict objectForKey:name] boolValue] forKey: name]; \
+	[defaults setBool:[[dict objectForKey:name] boolValue] forKey: name]; \
 }
 
 #define setFloatDefault(name) \
 { \
-	if ([[defaultValues() objectForKey: name] isEqual: [dict objectForKey: name]]) \
-		[defaults removeObjectForKey: name]; \
-	else \
-		[defaults setFloat:[[dict objectForKey:name] floatValue] forKey: name]; \
+	[defaults setFloat:[[dict objectForKey:name] floatValue] forKey: name]; \
 }
 
 #define setIntDefault(name) \
 { \
-	if ([[defaultValues() objectForKey:name] isEqual:[dict objectForKey:name]]) \
-		[defaults removeObjectForKey:name]; \
-	else \
-		[defaults setInteger:[[dict objectForKey:name] intValue] forKey:name]; \
+	[defaults setInteger:[[dict objectForKey:name] intValue] forKey:name]; \
 }
 
 #define setStringDefault(name) \
 { \
-	if ([[defaultValues() objectForKey:name] isEqual: [dict objectForKey: name]]) \
-		[defaults removeObjectForKey: name]; \
-	else \
-		[defaults setObject: [[dict objectForKey: name] stringValue] forKey: name]; \
+	[defaults setObject: [dict objectForKey: name] forKey: name]; \
 }
 
-+ (void) savePreferencesToDefaults: (NSDictionary *) dict
+- (void) savePreferencesToDefaults: (NSDictionary *) dict
 {
 	NSUserDefaults	*defaults = [NSUserDefaults standardUserDefaults];
 
+	NSLog (@"Updating defaults...");
 	setStringDefault(ProjectPath);
 	setStringDefault(BspSoundPath);
-	setIntDefault(StartWad);
+	setStringDefault(StartWad);
 	setFloatDefault(XLight);
 	setFloatDefault(YLight);
 	setFloatDefault(ZLight);
 	setBoolDefault(ShowBSPOutput);
 	setBoolDefault(OffsetBrushCopy);
+	[defaults synchronize];
 }
 
 @end
diff --git a/tools/Forge/main.m b/tools/Forge/main.m
index 53d74c0fa..f965f9bb0 100644
--- a/tools/Forge/main.m
+++ b/tools/Forge/main.m
@@ -1,6 +1,7 @@
 #import <AppKit/NSApplication.h>
+#import "Controller.h"
 
-#define APP_NAME @"GNUstep"
+#define APP_NAME @"Forge"
 
 int main(int argc, const char *argv[], const char *env[]) 
 {