Browse Source

Moved item list into main window. Drag & drop works.

preble 13 years ago
parent
commit
185a0e7889

+ 264 - 132
English.lproj/MainMenu.xib

@@ -490,9 +490,9 @@
 				<string key="NSName">_NSMainMenu</string>
 			</object>
 			<object class="NSWindowTemplate" id="972006081">
-				<int key="NSWindowStyleMask">15</int>
+				<int key="NSWindowStyleMask">7</int>
 				<int key="NSWindowBacking">2</int>
-				<string key="NSWindowRect">{{431, 250}, {728, 475}}</string>
+				<string key="NSWindowRect">{{431, 251}, {744, 474}}</string>
 				<int key="NSWTFlags">1954021376</int>
 				<string key="NSWindowTitle">Inside Job</string>
 				<string key="NSWindowClass">NSWindow</string>
@@ -506,7 +506,7 @@
 						<object class="NSTextField" id="574149520">
 							<reference key="NSNextResponder" ref="439893737"/>
 							<int key="NSvFlags">266</int>
-							<string key="NSFrame">{{211, 448}, {509, 14}}</string>
+							<string key="NSFrame">{{211, 447}, {525, 14}}</string>
 							<reference key="NSSuperview" ref="439893737"/>
 							<bool key="NSEnabled">YES</bool>
 							<object class="NSTextFieldCell" key="NSCell" id="828498206">
@@ -542,7 +542,7 @@
 						<object class="NSTextField" id="395301483">
 							<reference key="NSNextResponder" ref="439893737"/>
 							<int key="NSvFlags">268</int>
-							<string key="NSFrame">{{53, 409}, {85, 19}}</string>
+							<string key="NSFrame">{{53, 408}, {85, 19}}</string>
 							<reference key="NSSuperview" ref="439893737"/>
 							<bool key="NSEnabled">YES</bool>
 							<object class="NSTextFieldCell" key="NSCell" id="52955396">
@@ -585,7 +585,7 @@
 									</object>
 									<object class="NSAttributedString" key="NS.nan">
 										<string key="NSString">NaN</string>
-										<object class="NSDictionary" key="NSAttributes" id="258170481">
+										<object class="NSDictionary" key="NSAttributes" id="203469606">
 											<bool key="EncodedWithXMLCoder">YES</bool>
 											<object class="NSArray" key="dict.sortedKeys" id="0">
 												<bool key="EncodedWithXMLCoder">YES</bool>
@@ -595,7 +595,7 @@
 											</object>
 										</object>
 									</object>
-									<object class="NSDecimalNumberPlaceholder" key="NS.min" id="382513882">
+									<object class="NSDecimalNumberPlaceholder" key="NS.min" id="1028447999">
 										<int key="NS.exponent">0</int>
 										<int key="NS.length">0</int>
 										<bool key="NS.negative">YES</bool>
@@ -603,7 +603,7 @@
 										<int key="NS.mantissa.bo">1</int>
 										<bytes key="NS.mantissa">AAAAAAAAAAAAAAAAAAAAAA</bytes>
 									</object>
-									<reference key="NS.max" ref="382513882"/>
+									<reference key="NS.max" ref="1028447999"/>
 									<object class="NSDecimalNumberHandler" key="NS.rounding">
 										<int key="NS.roundingmode">3</int>
 										<bool key="NS.raise.overflow">YES</bool>
@@ -638,7 +638,7 @@
 						<object class="NSTextField" id="924742053">
 							<reference key="NSNextResponder" ref="439893737"/>
 							<int key="NSvFlags">268</int>
-							<string key="NSFrame">{{8, 411}, {40, 14}}</string>
+							<string key="NSFrame">{{8, 410}, {40, 14}}</string>
 							<reference key="NSSuperview" ref="439893737"/>
 							<bool key="NSEnabled">YES</bool>
 							<object class="NSTextFieldCell" key="NSCell" id="421186712">
@@ -654,7 +654,7 @@
 						<object class="NSBox" id="263108995">
 							<reference key="NSNextResponder" ref="439893737"/>
 							<int key="NSvFlags">10</int>
-							<string key="NSFrame">{{0, 434}, {728, 5}}</string>
+							<string key="NSFrame">{{0, 433}, {744, 5}}</string>
 							<reference key="NSSuperview" ref="439893737"/>
 							<string key="NSOffsets">{0, 0}</string>
 							<object class="NSTextFieldCell" key="NSTitleCell">
@@ -680,7 +680,7 @@
 						<object class="NSSegmentedControl" id="626341130">
 							<reference key="NSNextResponder" ref="439893737"/>
 							<int key="NSvFlags">268</int>
-							<string key="NSFrame">{{11, 443}, {195, 25}}</string>
+							<string key="NSFrame">{{11, 442}, {195, 25}}</string>
 							<reference key="NSSuperview" ref="439893737"/>
 							<bool key="NSEnabled">YES</bool>
 							<object class="NSSegmentedCell" key="NSCell" id="587756353">
@@ -724,39 +724,39 @@
 								<int key="NSSegmentStyle">2</int>
 							</object>
 						</object>
-						<object class="NSCustomView" id="132697522">
+						<object class="NSCustomView" id="971078756">
 							<reference key="NSNextResponder" ref="439893737"/>
 							<int key="NSvFlags">268</int>
-							<string key="NSFrame">{{78, 247}, {432, 144}}</string>
+							<string key="NSFrame">{{78, 246}, {432, 144}}</string>
 							<reference key="NSSuperview" ref="439893737"/>
 							<string key="NSClassName">IJInventoryView</string>
 						</object>
-						<object class="NSCustomView" id="1020331203">
+						<object class="NSCustomView" id="935002701">
 							<reference key="NSNextResponder" ref="439893737"/>
 							<int key="NSvFlags">268</int>
-							<string key="NSFrame">{{78, 180}, {432, 48}}</string>
+							<string key="NSFrame">{{78, 179}, {432, 48}}</string>
 							<reference key="NSSuperview" ref="439893737"/>
 							<string key="NSClassName">IJInventoryView</string>
 						</object>
-						<object class="NSCustomView" id="484221308">
+						<object class="NSCustomView" id="404767995">
 							<reference key="NSNextResponder" ref="439893737"/>
 							<int key="NSvFlags">268</int>
-							<string key="NSFrame">{{11, 199}, {48, 192}}</string>
+							<string key="NSFrame">{{11, 198}, {48, 192}}</string>
 							<reference key="NSSuperview" ref="439893737"/>
 							<string key="NSClassName">IJInventoryView</string>
 						</object>
-						<object class="NSSearchField" id="702959853">
+						<object class="NSSearchField" id="546340560">
 							<reference key="NSNextResponder" ref="439893737"/>
 							<int key="NSvFlags">265</int>
-							<string key="NSFrame">{{565, 406}, {152, 22}}</string>
+							<string key="NSFrame">{{556, 405}, {177, 22}}</string>
 							<reference key="NSSuperview" ref="439893737"/>
 							<bool key="NSEnabled">YES</bool>
-							<object class="NSSearchFieldCell" key="NSCell" id="55629982">
+							<object class="NSSearchFieldCell" key="NSCell" id="106296">
 								<int key="NSCellFlags">343014976</int>
 								<int key="NSCellFlags2">268436544</int>
 								<string key="NSContents"/>
 								<reference key="NSSupport" ref="731765667"/>
-								<reference key="NSControlView" ref="702959853"/>
+								<reference key="NSControlView" ref="546340560"/>
 								<bool key="NSDrawsBackground">YES</bool>
 								<int key="NSTextBezelStyle">1</int>
 								<reference key="NSBackgroundColor" ref="61377669"/>
@@ -765,9 +765,9 @@
 									<int key="NSCellFlags">130560</int>
 									<int key="NSCellFlags2">0</int>
 									<string key="NSContents">search</string>
-									<reference key="NSControlView" ref="702959853"/>
+									<reference key="NSControlView" ref="546340560"/>
 									<string key="NSAction">_searchFieldSearch:</string>
-									<reference key="NSTarget" ref="55629982"/>
+									<reference key="NSTarget" ref="106296"/>
 									<int key="NSButtonFlags">138690815</int>
 									<int key="NSButtonFlags2">0</int>
 									<string key="NSKeyEquivalent"/>
@@ -794,9 +794,9 @@
 											</object>
 										</object>
 									</object>
-									<reference key="NSControlView" ref="702959853"/>
+									<reference key="NSControlView" ref="546340560"/>
 									<string key="NSAction">_searchFieldCancel:</string>
-									<reference key="NSTarget" ref="55629982"/>
+									<reference key="NSTarget" ref="106296"/>
 									<int key="NSButtonFlags">138690815</int>
 									<int key="NSButtonFlags2">0</int>
 									<string key="NSKeyEquivalent"/>
@@ -804,32 +804,34 @@
 									<int key="NSPeriodicInterval">75</int>
 								</object>
 								<int key="NSMaximumRecents">255</int>
+								<bytes key="NSSearchFieldFlags">CAAAAA</bytes>
 							</object>
 						</object>
-						<object class="NSScrollView" id="590922788">
+						<object class="NSScrollView" id="846187987">
 							<reference key="NSNextResponder" ref="439893737"/>
-							<int key="NSvFlags">273</int>
+							<int key="NSvFlags">4369</int>
 							<object class="NSMutableArray" key="NSSubviews">
 								<bool key="EncodedWithXMLCoder">YES</bool>
-								<object class="NSClipView" id="178481444">
-									<reference key="NSNextResponder" ref="590922788"/>
+								<object class="NSClipView" id="545233995">
+									<reference key="NSNextResponder" ref="846187987"/>
 									<int key="NSvFlags">2304</int>
 									<object class="NSMutableArray" key="NSSubviews">
 										<bool key="EncodedWithXMLCoder">YES</bool>
-										<object class="NSTableView" id="777763986">
-											<reference key="NSNextResponder" ref="178481444"/>
-											<int key="NSvFlags">256</int>
-											<string key="NSFrameSize">{173, 397}</string>
-											<reference key="NSSuperview" ref="178481444"/>
+										<object class="NSTableView" id="890218557">
+											<reference key="NSNextResponder" ref="545233995"/>
+											<int key="NSvFlags">4352</int>
+											<string key="NSFrameSize">{205, 396}</string>
+											<reference key="NSSuperview" ref="545233995"/>
 											<bool key="NSEnabled">YES</bool>
 											<object class="_NSCornerView" key="NSCornerView">
 												<nil key="NSNextResponder"/>
 												<int key="NSvFlags">-2147483392</int>
-												<string key="NSFrame">{{224, 0}, {16, 17}}</string>
+												<string key="NSFrame">{{191, 0}, {16, 17}}</string>
 											</object>
 											<object class="NSMutableArray" key="NSTableColumns">
 												<bool key="EncodedWithXMLCoder">YES</bool>
-												<object class="NSTableColumn" id="209019532">
+												<object class="NSTableColumn" id="457307628">
+													<string key="NSIdentifier">itemId</string>
 													<double key="NSWidth">40</double>
 													<double key="NSMinWidth">40</double>
 													<double key="NSMaxWidth">1000</double>
@@ -838,7 +840,7 @@
 														<int key="NSCellFlags2">2048</int>
 														<string key="NSContents"/>
 														<reference key="NSSupport" ref="26"/>
-														<object class="NSColor" key="NSBackgroundColor" id="813226427">
+														<object class="NSColor" key="NSBackgroundColor" id="1049587905">
 															<int key="NSColorSpace">3</int>
 															<bytes key="NSWhite">MC4zMzMzMzI5ODU2AA</bytes>
 														</object>
@@ -849,12 +851,12 @@
 															<reference key="NSColor" ref="795034080"/>
 														</object>
 													</object>
-													<object class="NSTextFieldCell" key="NSDataCell" id="466831328">
+													<object class="NSTextFieldCell" key="NSDataCell" id="174398824">
 														<int key="NSCellFlags">337772096</int>
 														<int key="NSCellFlags2">-2080372736</int>
 														<string key="NSContents">Text Cell</string>
 														<reference key="NSSupport" ref="731765667"/>
-														<object class="NSNumberFormatter" key="NSFormatter" id="636090709">
+														<object class="NSNumberFormatter" key="NSFormatter" id="893402973">
 															<object class="NSMutableDictionary" key="NS.attributes">
 																<bool key="EncodedWithXMLCoder">YES</bool>
 																<object class="NSArray" key="dict.sortedKeys">
@@ -886,10 +888,10 @@
 															</object>
 															<object class="NSAttributedString" key="NS.nan">
 																<string key="NSString">NaN</string>
-																<reference key="NSAttributes" ref="258170481"/>
+																<reference key="NSAttributes" ref="203469606"/>
 															</object>
-															<reference key="NS.min" ref="382513882"/>
-															<reference key="NS.max" ref="382513882"/>
+															<reference key="NS.min" ref="1028447999"/>
+															<reference key="NS.max" ref="1028447999"/>
 															<object class="NSDecimalNumberHandler" key="NS.rounding">
 																<int key="NS.roundingmode">3</int>
 																<bool key="NS.raise.overflow">YES</bool>
@@ -902,7 +904,7 @@
 															<bool key="NS.localized">NO</bool>
 															<bool key="NS.allowsfloats">YES</bool>
 														</object>
-														<reference key="NSControlView" ref="777763986"/>
+														<reference key="NSControlView" ref="890218557"/>
 														<object class="NSColor" key="NSBackgroundColor" id="451382550">
 															<int key="NSColorSpace">6</int>
 															<string key="NSCatalogName">System</string>
@@ -914,10 +916,43 @@
 													<int key="NSResizingMask">3</int>
 													<bool key="NSIsResizeable">YES</bool>
 													<bool key="NSIsEditable">YES</bool>
-													<reference key="NSTableView" ref="777763986"/>
+													<reference key="NSTableView" ref="890218557"/>
 												</object>
-												<object class="NSTableColumn" id="724501441">
-													<double key="NSWidth">127</double>
+												<object class="NSTableColumn" id="195367098">
+													<string key="NSIdentifier">image</string>
+													<double key="NSWidth">32</double>
+													<double key="NSMinWidth">10</double>
+													<double key="NSMaxWidth">3.4028234663852886e+38</double>
+													<object class="NSTableHeaderCell" key="NSHeaderCell">
+														<int key="NSCellFlags">75628096</int>
+														<int key="NSCellFlags2">2048</int>
+														<string key="NSContents"/>
+														<reference key="NSSupport" ref="26"/>
+														<object class="NSColor" key="NSBackgroundColor">
+															<int key="NSColorSpace">6</int>
+															<string key="NSCatalogName">System</string>
+															<string key="NSColorName">headerColor</string>
+															<reference key="NSColor" ref="665547368"/>
+														</object>
+														<reference key="NSTextColor" ref="115003830"/>
+													</object>
+													<object class="NSImageCell" key="NSDataCell" id="1064994847">
+														<int key="NSCellFlags">67239424</int>
+														<int key="NSCellFlags2">33554432</int>
+														<reference key="NSSupport" ref="731765667"/>
+														<int key="NSAlign">0</int>
+														<int key="NSScale">0</int>
+														<int key="NSStyle">0</int>
+														<bool key="NSAnimates">NO</bool>
+													</object>
+													<int key="NSResizingMask">3</int>
+													<bool key="NSIsResizeable">YES</bool>
+													<bool key="NSIsEditable">YES</bool>
+													<reference key="NSTableView" ref="890218557"/>
+												</object>
+												<object class="NSTableColumn" id="107691055">
+													<string key="NSIdentifier">name</string>
+													<double key="NSWidth">124</double>
 													<double key="NSMinWidth">40</double>
 													<double key="NSMaxWidth">1000</double>
 													<object class="NSTableHeaderCell" key="NSHeaderCell">
@@ -925,22 +960,22 @@
 														<int key="NSCellFlags2">2048</int>
 														<string key="NSContents"/>
 														<reference key="NSSupport" ref="26"/>
-														<reference key="NSBackgroundColor" ref="813226427"/>
+														<reference key="NSBackgroundColor" ref="1049587905"/>
 														<reference key="NSTextColor" ref="115003830"/>
 													</object>
-													<object class="NSTextFieldCell" key="NSDataCell" id="790728365">
+													<object class="NSTextFieldCell" key="NSDataCell" id="439891406">
 														<int key="NSCellFlags">337772096</int>
 														<int key="NSCellFlags2">2048</int>
 														<string key="NSContents">Text Cell</string>
 														<reference key="NSSupport" ref="731765667"/>
-														<reference key="NSControlView" ref="777763986"/>
+														<reference key="NSControlView" ref="890218557"/>
 														<reference key="NSBackgroundColor" ref="451382550"/>
 														<reference key="NSTextColor" ref="915322728"/>
 													</object>
 													<int key="NSResizingMask">3</int>
 													<bool key="NSIsResizeable">YES</bool>
 													<bool key="NSIsEditable">YES</bool>
-													<reference key="NSTableView" ref="777763986"/>
+													<reference key="NSTableView" ref="890218557"/>
 												</object>
 											</object>
 											<double key="NSIntercellSpacingWidth">3</double>
@@ -956,7 +991,7 @@
 												</object>
 											</object>
 											<double key="NSRowHeight">17</double>
-											<int key="NSTvFlags">-700448768</int>
+											<int key="NSTvFlags">-767557632</int>
 											<reference key="NSDelegate"/>
 											<reference key="NSDataSource"/>
 											<int key="NSColumnAutoresizingStyle">4</int>
@@ -966,48 +1001,49 @@
 											<int key="NSTableViewDraggingDestinationStyle">0</int>
 										</object>
 									</object>
-									<string key="NSFrame">{{1, 1}, {173, 397}}</string>
-									<reference key="NSSuperview" ref="590922788"/>
-									<reference key="NSNextKeyView" ref="777763986"/>
-									<reference key="NSDocView" ref="777763986"/>
+									<string key="NSFrame">{{1, 1}, {205, 396}}</string>
+									<reference key="NSSuperview" ref="846187987"/>
+									<reference key="NSNextKeyView" ref="890218557"/>
+									<reference key="NSDocView" ref="890218557"/>
 									<reference key="NSBGColor" ref="451382550"/>
 									<int key="NScvFlags">4</int>
 								</object>
-								<object class="NSScroller" id="215570513">
-									<reference key="NSNextResponder" ref="590922788"/>
+								<object class="NSScroller" id="77446428">
+									<reference key="NSNextResponder" ref="846187987"/>
 									<int key="NSvFlags">-2147483392</int>
-									<string key="NSFrame">{{224, 17}, {15, 102}}</string>
-									<reference key="NSSuperview" ref="590922788"/>
-									<reference key="NSTarget" ref="590922788"/>
+									<string key="NSFrame">{{191, 17}, {15, 365}}</string>
+									<reference key="NSSuperview" ref="846187987"/>
+									<reference key="NSTarget" ref="846187987"/>
 									<string key="NSAction">_doScroller:</string>
-									<double key="NSPercent">0.99668874172185429</double>
+									<double key="NSPercent">0.9974811083123426</double>
 								</object>
-								<object class="NSScroller" id="1046458070">
-									<reference key="NSNextResponder" ref="590922788"/>
+								<object class="NSScroller" id="954038452">
+									<reference key="NSNextResponder" ref="846187987"/>
 									<int key="NSvFlags">-2147483392</int>
-									<string key="NSFrame">{{1, 119}, {223, 15}}</string>
-									<reference key="NSSuperview" ref="590922788"/>
+									<string key="NSFrame">{{1, 382}, {190, 15}}</string>
+									<reference key="NSSuperview" ref="846187987"/>
 									<int key="NSsFlags">1</int>
-									<reference key="NSTarget" ref="590922788"/>
+									<reference key="NSTarget" ref="846187987"/>
 									<string key="NSAction">_doScroller:</string>
-									<double key="NSPercent">0.99425287356321834</double>
+									<double key="NSPercent">0.99514563106796117</double>
 								</object>
 							</object>
-							<string key="NSFrame">{{554, -1}, {175, 399}}</string>
+							<string key="NSFrame">{{538, -1}, {207, 398}}</string>
 							<reference key="NSSuperview" ref="439893737"/>
-							<reference key="NSNextKeyView" ref="178481444"/>
+							<reference key="NSNextKeyView" ref="545233995"/>
 							<int key="NSsFlags">562</int>
-							<reference key="NSVScroller" ref="215570513"/>
-							<reference key="NSHScroller" ref="1046458070"/>
-							<reference key="NSContentView" ref="178481444"/>
+							<reference key="NSVScroller" ref="77446428"/>
+							<reference key="NSHScroller" ref="954038452"/>
+							<reference key="NSContentView" ref="545233995"/>
 							<bytes key="NSScrollAmts">QSAAAEEgAABBmAAAQZgAAA</bytes>
 						</object>
 					</object>
-					<string key="NSFrameSize">{728, 475}</string>
+					<string key="NSFrameSize">{744, 474}</string>
 					<reference key="NSSuperview"/>
 				</object>
 				<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
 				<string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
+				<string key="NSFrameAutosaveName">MainWindow</string>
 			</object>
 			<object class="NSCustomObject" id="976324537">
 				<string key="NSClassName">InsideJobAppDelegate</string>
@@ -1290,7 +1326,7 @@
 					<object class="IBOutletConnection" key="connection">
 						<string key="label">inventoryView</string>
 						<reference key="source" ref="760161335"/>
-						<reference key="destination" ref="132697522"/>
+						<reference key="destination" ref="971078756"/>
 					</object>
 					<int key="connectionID">642</int>
 				</object>
@@ -1298,7 +1334,7 @@
 					<object class="IBOutletConnection" key="connection">
 						<string key="label">armorView</string>
 						<reference key="source" ref="760161335"/>
-						<reference key="destination" ref="484221308"/>
+						<reference key="destination" ref="404767995"/>
 					</object>
 					<int key="connectionID">645</int>
 				</object>
@@ -1306,10 +1342,58 @@
 					<object class="IBOutletConnection" key="connection">
 						<string key="label">quickView</string>
 						<reference key="source" ref="760161335"/>
-						<reference key="destination" ref="1020331203"/>
+						<reference key="destination" ref="935002701"/>
 					</object>
 					<int key="connectionID">646</int>
 				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">itemSearchField</string>
+						<reference key="source" ref="760161335"/>
+						<reference key="destination" ref="546340560"/>
+					</object>
+					<int key="connectionID">659</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">itemTableView</string>
+						<reference key="source" ref="760161335"/>
+						<reference key="destination" ref="890218557"/>
+					</object>
+					<int key="connectionID">660</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">dataSource</string>
+						<reference key="source" ref="890218557"/>
+						<reference key="destination" ref="760161335"/>
+					</object>
+					<int key="connectionID">661</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">delegate</string>
+						<reference key="source" ref="890218557"/>
+						<reference key="destination" ref="760161335"/>
+					</object>
+					<int key="connectionID">662</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">updateItemSearchFilter:</string>
+						<reference key="source" ref="760161335"/>
+						<reference key="destination" ref="546340560"/>
+					</object>
+					<int key="connectionID">663</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">initialFirstResponder</string>
+						<reference key="source" ref="972006081"/>
+						<reference key="destination" ref="546340560"/>
+					</object>
+					<int key="connectionID">668</int>
+				</object>
 			</object>
 			<object class="IBMutableOrderedSet" key="objectRecords">
 				<object class="NSArray" key="orderedObjects">
@@ -1681,11 +1765,11 @@
 							<reference ref="395301483"/>
 							<reference ref="574149520"/>
 							<reference ref="626341130"/>
-							<reference ref="484221308"/>
-							<reference ref="132697522"/>
-							<reference ref="1020331203"/>
-							<reference ref="702959853"/>
-							<reference ref="590922788"/>
+							<reference ref="404767995"/>
+							<reference ref="971078756"/>
+							<reference ref="935002701"/>
+							<reference ref="546340560"/>
+							<reference ref="846187987"/>
 						</object>
 						<reference key="parent" ref="972006081"/>
 					</object>
@@ -1799,7 +1883,7 @@
 					</object>
 					<object class="IBObjectRecord">
 						<int key="objectID">641</int>
-						<reference key="object" ref="132697522"/>
+						<reference key="object" ref="971078756"/>
 						<object class="NSMutableArray" key="children">
 							<bool key="EncodedWithXMLCoder">YES</bool>
 						</object>
@@ -1807,95 +1891,110 @@
 					</object>
 					<object class="IBObjectRecord">
 						<int key="objectID">643</int>
-						<reference key="object" ref="1020331203"/>
+						<reference key="object" ref="935002701"/>
 						<reference key="parent" ref="439893737"/>
 					</object>
 					<object class="IBObjectRecord">
 						<int key="objectID">644</int>
-						<reference key="object" ref="484221308"/>
+						<reference key="object" ref="404767995"/>
 						<reference key="parent" ref="439893737"/>
 					</object>
 					<object class="IBObjectRecord">
 						<int key="objectID">647</int>
-						<reference key="object" ref="702959853"/>
+						<reference key="object" ref="546340560"/>
 						<object class="NSMutableArray" key="children">
 							<bool key="EncodedWithXMLCoder">YES</bool>
-							<reference ref="55629982"/>
+							<reference ref="106296"/>
 						</object>
 						<reference key="parent" ref="439893737"/>
 					</object>
 					<object class="IBObjectRecord">
 						<int key="objectID">648</int>
-						<reference key="object" ref="55629982"/>
-						<reference key="parent" ref="702959853"/>
+						<reference key="object" ref="106296"/>
+						<reference key="parent" ref="546340560"/>
 					</object>
 					<object class="IBObjectRecord">
 						<int key="objectID">649</int>
-						<reference key="object" ref="590922788"/>
+						<reference key="object" ref="846187987"/>
 						<object class="NSMutableArray" key="children">
 							<bool key="EncodedWithXMLCoder">YES</bool>
-							<reference ref="215570513"/>
-							<reference ref="1046458070"/>
-							<reference ref="777763986"/>
+							<reference ref="77446428"/>
+							<reference ref="954038452"/>
+							<reference ref="890218557"/>
 						</object>
 						<reference key="parent" ref="439893737"/>
 					</object>
 					<object class="IBObjectRecord">
 						<int key="objectID">650</int>
-						<reference key="object" ref="215570513"/>
-						<reference key="parent" ref="590922788"/>
+						<reference key="object" ref="77446428"/>
+						<reference key="parent" ref="846187987"/>
 					</object>
 					<object class="IBObjectRecord">
 						<int key="objectID">651</int>
-						<reference key="object" ref="1046458070"/>
-						<reference key="parent" ref="590922788"/>
+						<reference key="object" ref="954038452"/>
+						<reference key="parent" ref="846187987"/>
 					</object>
 					<object class="IBObjectRecord">
 						<int key="objectID">652</int>
-						<reference key="object" ref="777763986"/>
+						<reference key="object" ref="890218557"/>
 						<object class="NSMutableArray" key="children">
 							<bool key="EncodedWithXMLCoder">YES</bool>
-							<reference ref="209019532"/>
-							<reference ref="724501441"/>
+							<reference ref="457307628"/>
+							<reference ref="107691055"/>
+							<reference ref="195367098"/>
 						</object>
-						<reference key="parent" ref="590922788"/>
+						<reference key="parent" ref="846187987"/>
 					</object>
 					<object class="IBObjectRecord">
 						<int key="objectID">654</int>
-						<reference key="object" ref="209019532"/>
+						<reference key="object" ref="457307628"/>
 						<object class="NSMutableArray" key="children">
 							<bool key="EncodedWithXMLCoder">YES</bool>
-							<reference ref="466831328"/>
+							<reference ref="174398824"/>
 						</object>
-						<reference key="parent" ref="777763986"/>
+						<reference key="parent" ref="890218557"/>
 					</object>
 					<object class="IBObjectRecord">
 						<int key="objectID">655</int>
-						<reference key="object" ref="724501441"/>
+						<reference key="object" ref="107691055"/>
 						<object class="NSMutableArray" key="children">
 							<bool key="EncodedWithXMLCoder">YES</bool>
-							<reference ref="790728365"/>
+							<reference ref="439891406"/>
 						</object>
-						<reference key="parent" ref="777763986"/>
+						<reference key="parent" ref="890218557"/>
 					</object>
 					<object class="IBObjectRecord">
 						<int key="objectID">656</int>
-						<reference key="object" ref="790728365"/>
-						<reference key="parent" ref="724501441"/>
+						<reference key="object" ref="439891406"/>
+						<reference key="parent" ref="107691055"/>
 					</object>
 					<object class="IBObjectRecord">
 						<int key="objectID">657</int>
-						<reference key="object" ref="466831328"/>
+						<reference key="object" ref="174398824"/>
 						<object class="NSMutableArray" key="children">
 							<bool key="EncodedWithXMLCoder">YES</bool>
-							<reference ref="636090709"/>
+							<reference ref="893402973"/>
 						</object>
-						<reference key="parent" ref="209019532"/>
+						<reference key="parent" ref="457307628"/>
 					</object>
 					<object class="IBObjectRecord">
 						<int key="objectID">658</int>
-						<reference key="object" ref="636090709"/>
-						<reference key="parent" ref="466831328"/>
+						<reference key="object" ref="893402973"/>
+						<reference key="parent" ref="174398824"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">665</int>
+						<reference key="object" ref="195367098"/>
+						<object class="NSMutableArray" key="children">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<reference ref="1064994847"/>
+						</object>
+						<reference key="parent" ref="890218557"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">667</int>
+						<reference key="object" ref="1064994847"/>
+						<reference key="parent" ref="195367098"/>
 					</object>
 				</object>
 			</object>
@@ -2043,6 +2142,7 @@
 					<string>658.IBNumberFormatterBehaviorMetadataKey</string>
 					<string>658.IBNumberFormatterLocalizesFormatMetadataKey</string>
 					<string>658.IBPluginDependency</string>
+					<string>667.IBPluginDependency</string>
 					<string>74.IBPluginDependency</string>
 					<string>74.ImportedFromIB2</string>
 					<string>75.IBPluginDependency</string>
@@ -2142,9 +2242,9 @@
 					<string>{{475, 832}, {234, 43}}</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
-					<string>{{80, 119}, {728, 475}}</string>
+					<string>{{34, 169}, {744, 474}}</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
-					<string>{{80, 119}, {728, 475}}</string>
+					<string>{{34, 169}, {744, 474}}</string>
 					<integer value="1"/>
 					<string>{{33, 99}, {480, 360}}</string>
 					<string>{3.40282e+38, 3.40282e+38}</string>
@@ -2226,6 +2326,7 @@
 					<boolean value="YES"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<integer value="1"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<integer value="1"/>
@@ -2259,7 +2360,7 @@
 				</object>
 			</object>
 			<nil key="sourceID"/>
-			<int key="maxID">658</int>
+			<int key="maxID">668</int>
 		</object>
 		<object class="IBClassDescriber" key="IBDocument.Classes">
 			<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -2287,14 +2388,35 @@
 					<string key="className">IJInventoryWindowController</string>
 					<string key="superclassName">NSWindowController</string>
 					<object class="NSMutableDictionary" key="actions">
-						<string key="NS.key.0">worldSelectionChanged:</string>
-						<string key="NS.object.0">id</string>
+						<bool key="EncodedWithXMLCoder">YES</bool>
+						<object class="NSArray" key="dict.sortedKeys">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<string>updateItemSearchFilter:</string>
+							<string>worldSelectionChanged:</string>
+						</object>
+						<object class="NSMutableArray" key="dict.values">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<string>id</string>
+							<string>id</string>
+						</object>
 					</object>
 					<object class="NSMutableDictionary" key="actionInfosByName">
-						<string key="NS.key.0">worldSelectionChanged:</string>
-						<object class="IBActionInfo" key="NS.object.0">
-							<string key="name">worldSelectionChanged:</string>
-							<string key="candidateClassName">id</string>
+						<bool key="EncodedWithXMLCoder">YES</bool>
+						<object class="NSArray" key="dict.sortedKeys">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<string>updateItemSearchFilter:</string>
+							<string>worldSelectionChanged:</string>
+						</object>
+						<object class="NSMutableArray" key="dict.values">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<object class="IBActionInfo">
+								<string key="name">updateItemSearchFilter:</string>
+								<string key="candidateClassName">id</string>
+							</object>
+							<object class="IBActionInfo">
+								<string key="name">worldSelectionChanged:</string>
+								<string key="candidateClassName">id</string>
+							</object>
 						</object>
 					</object>
 					<object class="NSMutableDictionary" key="outlets">
@@ -2303,7 +2425,8 @@
 							<bool key="EncodedWithXMLCoder">YES</bool>
 							<string>armorView</string>
 							<string>inventoryView</string>
-							<string>outlineView</string>
+							<string>itemSearchField</string>
+							<string>itemTableView</string>
 							<string>quickView</string>
 							<string>statusTextField</string>
 							<string>worldSelectionControl</string>
@@ -2312,7 +2435,8 @@
 							<bool key="EncodedWithXMLCoder">YES</bool>
 							<string>IJInventoryView</string>
 							<string>IJInventoryView</string>
-							<string>NSOutlineView</string>
+							<string>NSSearchField</string>
+							<string>NSTableView</string>
 							<string>IJInventoryView</string>
 							<string>NSTextField</string>
 							<string>NSSegmentedControl</string>
@@ -2324,7 +2448,8 @@
 							<bool key="EncodedWithXMLCoder">YES</bool>
 							<string>armorView</string>
 							<string>inventoryView</string>
-							<string>outlineView</string>
+							<string>itemSearchField</string>
+							<string>itemTableView</string>
 							<string>quickView</string>
 							<string>statusTextField</string>
 							<string>worldSelectionControl</string>
@@ -2340,8 +2465,12 @@
 								<string key="candidateClassName">IJInventoryView</string>
 							</object>
 							<object class="IBToOneOutletInfo">
-								<string key="name">outlineView</string>
-								<string key="candidateClassName">NSOutlineView</string>
+								<string key="name">itemSearchField</string>
+								<string key="candidateClassName">NSSearchField</string>
+							</object>
+							<object class="IBToOneOutletInfo">
+								<string key="name">itemTableView</string>
+								<string key="candidateClassName">NSTableView</string>
 							</object>
 							<object class="IBToOneOutletInfo">
 								<string key="name">quickView</string>
@@ -2558,6 +2687,14 @@
 						<string key="minorKey">Foundation.framework/Headers/NSFormatter.h</string>
 					</object>
 				</object>
+				<object class="IBPartialClassDescription">
+					<string key="className">NSImageCell</string>
+					<string key="superclassName">NSCell</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBFrameworkSource</string>
+						<string key="minorKey">AppKit.framework/Headers/NSImageCell.h</string>
+					</object>
+				</object>
 				<object class="IBPartialClassDescription">
 					<string key="className">NSMatrix</string>
 					<string key="superclassName">NSControl</string>
@@ -2666,7 +2803,7 @@
 				</object>
 				<object class="IBPartialClassDescription">
 					<string key="className">NSObject</string>
-					<object class="IBClassDescriptionSource" key="sourceIdentifier" id="741829912">
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
 						<string key="majorKey">IBFrameworkSource</string>
 						<string key="minorKey">AppKit.framework/Headers/NSOutlineView.h</string>
 					</object>
@@ -2860,11 +2997,6 @@
 						<string key="minorKey">QuartzCore.framework/Headers/CIImageProvider.h</string>
 					</object>
 				</object>
-				<object class="IBPartialClassDescription">
-					<string key="className">NSOutlineView</string>
-					<string key="superclassName">NSTableView</string>
-					<reference key="sourceIdentifier" ref="741829912"/>
-				</object>
 				<object class="IBPartialClassDescription">
 					<string key="className">NSResponder</string>
 					<object class="IBClassDescriptionSource" key="sourceIdentifier">

+ 2 - 0
IJInventoryItem.h

@@ -35,4 +35,6 @@
 
 + (NSDictionary *)itemIdLookup;
 
++ (NSImage *)imageForItemId:(uint16_t)itemId;
+
 @end

+ 18 - 13
IJInventoryItem.m

@@ -50,7 +50,7 @@
 		return [NSString stringWithFormat:@"%d", self.itemId];
 }
 
-- (NSImage *)image
++ (NSImage *)imageForItemId:(uint16_t)itemId
 {
 	NSSize itemImageSize = NSMakeSize(32, 32);
 	NSPoint atlasOffset;
@@ -60,29 +60,29 @@
 	
 	int index;
 	
-	if (self.itemId <= 85)
+	if (itemId <= 85)
 	{
-		if (self.itemId <= 20)
-			index = self.itemId - 1; // first item is 1
-		else if (self.itemId == 35)
-			index = self.itemId - (35 - 20);
-		else if (self.itemId >= 37)
-			index = self.itemId - (37 - 21);
+		if (itemId <= 20)
+			index = itemId - 1; // first item is 1
+		else if (itemId == 35)
+			index = itemId - (35 - 20);
+		else if (itemId >= 37)
+			index = itemId - (37 - 21);
 		atlasOffset = NSMakePoint(36, 75);
 	}
-	else if (self.itemId >= 256 && self.itemId <= 346)
+	else if (itemId >= 256 && itemId <= 346)
 	{
-		index = self.itemId - 256;
+		index = itemId - 256;
 		atlasOffset = NSMakePoint(445, 23+52);
 	}
-	else if (self.itemId >= 2556 && self.itemId <= 2557)
+	else if (itemId >= 2556 && itemId <= 2557)
 	{
-		index = self.itemId - 2556;
+		index = itemId - 2556;
 		atlasOffset = NSMakePoint(445+pixelsPerColumn, 23+52);
 	}
 	else
 	{
-		NSLog(@"%s error: unrecognized item id %d", __PRETTY_FUNCTION__, self.itemId);
+		NSLog(@"%s error: unrecognized item id %d", __PRETTY_FUNCTION__, itemId);
 		return nil;
 	}
 
@@ -113,6 +113,11 @@
 	return output;
 }
 
+- (NSImage *)image
+{
+	return [IJInventoryItem imageForItemId:itemId];
+}
+
 + (NSDictionary *)itemIdLookup
 {
 	static NSDictionary *lookup = nil;

+ 2 - 0
IJInventoryView.h

@@ -8,6 +8,8 @@
 
 #import <Cocoa/Cocoa.h>
 
+extern NSString * const IJPasteboardTypeInventoryItem;
+
 @protocol IJInventoryViewDelegate;
 @class IJInventoryItem;
 

+ 5 - 0
IJInventoryWindowController.h

@@ -30,6 +30,8 @@
 	// Search/Item List
 	NSSearchField *itemSearchField;
 	NSTableView *itemTableView;
+	NSArray *allItemIds;
+	NSArray *filteredItemIds;
 	
 	// Document
 	BOOL dirty;
@@ -41,9 +43,12 @@
 @property (nonatomic, assign) IBOutlet IJInventoryView *inventoryView;
 @property (nonatomic, assign) IBOutlet IJInventoryView *quickView;
 @property (nonatomic, assign) IBOutlet IJInventoryView *armorView;
+@property (nonatomic, assign) IBOutlet NSSearchField *itemSearchField;
+@property (nonatomic, assign) IBOutlet NSTableView *itemTableView;
 
 @property (nonatomic, retain) NSNumber *worldTime;
 
 - (IBAction)worldSelectionChanged:(id)sender;
+- (IBAction)updateItemSearchFilter:(id)sender;
 
 @end

+ 79 - 0
IJInventoryWindowController.m

@@ -17,6 +17,7 @@
 @synthesize worldSelectionControl;
 @synthesize statusTextField;
 @synthesize inventoryView, armorView, quickView;
+@synthesize itemSearchField, itemTableView;
 
 
 - (void)awakeFromNib
@@ -32,6 +33,12 @@
 	inventoryView.delegate = self;
 	quickView.delegate = self;
 	armorView.delegate = self;
+
+	// Item Table View setup
+	NSArray *keys = [[IJInventoryItem itemIdLookup] allKeys];
+	keys = [keys sortedArrayUsingSelector:@selector(compare:)];
+	allItemIds = [[NSArray alloc] initWithArray:keys];
+	filteredItemIds = [allItemIds retain];
 }
 
 - (void)dealloc
@@ -278,5 +285,77 @@
 #pragma mark Item Picker
 
 
+- (IBAction)updateItemSearchFilter:(id)sender
+{
+	NSString *filterString = [sender stringValue];
+	
+	if (filterString.length == 0)
+	{
+		[filteredItemIds autorelease];
+		filteredItemIds = [allItemIds retain];
+		[itemTableView reloadData];
+		return;
+	}
+	
+	NSMutableArray *results = [NSMutableArray array];
+	
+	for (NSNumber *itemId in allItemIds)
+	{
+		NSString *name = [[IJInventoryItem itemIdLookup] objectForKey:itemId];
+		NSRange range = [name rangeOfString:filterString options:NSCaseInsensitiveSearch];
+		if (range.location != NSNotFound)
+			[results addObject:itemId];
+	}
+	
+	[filteredItemIds autorelease];
+	filteredItemIds = [results retain];
+	[itemTableView reloadData];
+}
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)theTableView
+{
+	return filteredItemIds.count;
+}
+- (id)tableView:(NSTableView *)theTableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
+{
+	// TODO: Change this, because the row will not correspond once we support sorting.
+	NSNumber *itemId = [filteredItemIds objectAtIndex:row];
+	
+	if ([tableColumn.identifier isEqual:@"itemId"])
+	{
+		return itemId;
+	}
+	else if ([tableColumn.identifier isEqual:@"image"])
+	{
+		return [IJInventoryItem imageForItemId:[itemId shortValue]];
+	}
+	else
+	{
+		NSString *name = [[IJInventoryItem itemIdLookup] objectForKey:itemId];
+		return name;
+	}
+}
+- (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard
+{
+	[pboard declareTypes:[NSArray arrayWithObjects:IJPasteboardTypeInventoryItem, nil] owner:nil];
+	
+	NSNumber *itemId = [filteredItemIds objectAtIndex:[rowIndexes firstIndex]];
+	
+	IJInventoryItem *item = [[IJInventoryItem alloc] init];
+	item.itemId = [itemId shortValue];
+	item.count = 1;
+	item.damage = 0;
+	item.slot = 0;
+	
+	[pboard setData:[NSKeyedArchiver archivedDataWithRootObject:item]
+			forType:IJPasteboardTypeInventoryItem];
+	
+	[item release];
+
+	return YES;
+}
+
+
+
 
 @end

+ 14 - 0
InsideJob.xcodeproj/project.pbxproj

@@ -20,6 +20,7 @@
 		668B297C125E5DF00060BF71 /* ItemPicker.xib in Resources */ = {isa = PBXBuildFile; fileRef = 668B297B125E5DF00060BF71 /* ItemPicker.xib */; };
 		66BC00031260215C005A23F4 /* IJInventoryView.m in Sources */ = {isa = PBXBuildFile; fileRef = 66BC00021260215C005A23F4 /* IJInventoryView.m */; };
 		66BC000E12602359005A23F4 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66BC000D12602359005A23F4 /* QuartzCore.framework */; };
+		66BC033B1260CC59005A23F4 /* MAAttachedWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 66BC033A1260CC59005A23F4 /* MAAttachedWindow.m */; };
 		66BCFC2B125E9A51005A23F4 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 66BCFC2A125E9A51005A23F4 /* Credits.rtf */; };
 		66BCFC36125EA53E005A23F4 /* InsideJob.icns in Resources */ = {isa = PBXBuildFile; fileRef = 66BCFC35125EA53E005A23F4 /* InsideJob.icns */; };
 		66BCFE62125FCEC6005A23F4 /* DataValuesV110Transparent.png in Resources */ = {isa = PBXBuildFile; fileRef = 66BCFE61125FCEC6005A23F4 /* DataValuesV110Transparent.png */; };
@@ -57,6 +58,8 @@
 		66BC00011260215C005A23F4 /* IJInventoryView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJInventoryView.h; sourceTree = "<group>"; };
 		66BC00021260215C005A23F4 /* IJInventoryView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJInventoryView.m; sourceTree = "<group>"; };
 		66BC000D12602359005A23F4 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+		66BC03391260CC59005A23F4 /* MAAttachedWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MAAttachedWindow.h; sourceTree = "<group>"; };
+		66BC033A1260CC59005A23F4 /* MAAttachedWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MAAttachedWindow.m; sourceTree = "<group>"; };
 		66BCFC2A125E9A51005A23F4 /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = "<group>"; };
 		66BCFC35125EA53E005A23F4 /* InsideJob.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = InsideJob.icns; sourceTree = "<group>"; };
 		66BCFE61125FCEC6005A23F4 /* DataValuesV110Transparent.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DataValuesV110Transparent.png; sourceTree = "<group>"; };
@@ -85,6 +88,7 @@
 				256AC3D90F4B6AC300CF3369 /* InsideJobAppDelegate.m */,
 				668B27F3125D96470060BF71 /* Interface */,
 				668B2551125D59BF0060BF71 /* Model */,
+				66BC033E1260CC68005A23F4 /* Views & Windows */,
 				668B2559125D5BB90060BF71 /* Categories */,
 			);
 			name = Classes;
@@ -198,6 +202,15 @@
 			name = Interface;
 			sourceTree = "<group>";
 		};
+		66BC033E1260CC68005A23F4 /* Views & Windows */ = {
+			isa = PBXGroup;
+			children = (
+				66BC03391260CC59005A23F4 /* MAAttachedWindow.h */,
+				66BC033A1260CC59005A23F4 /* MAAttachedWindow.m */,
+			);
+			name = "Views & Windows";
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
@@ -277,6 +290,7 @@
 				668B27F2125D963F0060BF71 /* IJInventoryWindowController.m in Sources */,
 				668B2979125E5DD40060BF71 /* IJItemPickerWindowController.m in Sources */,
 				66BC00031260215C005A23F4 /* IJInventoryView.m in Sources */,
+				66BC033B1260CC59005A23F4 /* MAAttachedWindow.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 184 - 0
MAAttachedWindow.h

@@ -0,0 +1,184 @@
+//
+//  MAAttachedWindow.h
+//
+//  Created by Matt Gemmell on 27/09/2007.
+//  Copyright 2007 Magic Aubergine.
+//
+
+#import <Cocoa/Cocoa.h>
+
+/*
+ Below are the positions the attached window can be displayed at.
+ 
+ Note that these positions are relative to the point passed to the constructor, 
+ e.g. MAPositionBottomRight will put the window below the point and towards the right, 
+      MAPositionTop will horizontally center the window above the point, 
+      MAPositionRightTop will put the window to the right and above the point, 
+ and so on.
+ 
+ You can also pass MAPositionAutomatic (or use an initializer which omits the 'onSide:' 
+ argument) and the attached window will try to position itself sensibly, based on 
+ available screen-space.
+ 
+ Notes regarding automatically-positioned attached windows:
+ 
+ (a) The window prefers to position itself horizontally centered below the specified point.
+     This gives a certain enhanced visual sense of an attachment/relationship.
+ 
+ (b) The window will try to align itself with its parent window (if any); i.e. it will 
+     attempt to stay within its parent window's frame if it can.
+ 
+ (c) The algorithm isn't perfect. :) If in doubt, do your own calculations and then 
+     explicitly request that the window attach itself to a particular side.
+ */
+
+typedef enum _MAWindowPosition {
+    // The four primary sides are compatible with the preferredEdge of NSDrawer.
+    MAPositionLeft          = NSMinXEdge, // 0
+    MAPositionRight         = NSMaxXEdge, // 2
+    MAPositionTop           = NSMaxYEdge, // 3
+    MAPositionBottom        = NSMinYEdge, // 1
+    MAPositionLeftTop       = 4,
+    MAPositionLeftBottom    = 5,
+    MAPositionRightTop      = 6,
+    MAPositionRightBottom   = 7,
+    MAPositionTopLeft       = 8,
+    MAPositionTopRight      = 9,
+    MAPositionBottomLeft    = 10,
+    MAPositionBottomRight   = 11,
+    MAPositionAutomatic     = 12
+} MAWindowPosition;
+
+@interface MAAttachedWindow : NSWindow {
+    NSColor *borderColor;
+    float borderWidth;
+    float viewMargin;
+    float arrowBaseWidth;
+    float arrowHeight;
+    BOOL hasArrow;
+    float cornerRadius;
+    BOOL drawsRoundCornerBesideArrow;
+    
+    @private
+    NSColor *_MABackgroundColor;
+    __weak NSView *_view;
+    __weak NSWindow *_window;
+    NSPoint _point;
+    MAWindowPosition _side;
+    float _distance;
+    NSRect _viewFrame;
+    BOOL _resizing;
+}
+
+/*
+ Initialization methods
+ 
+ Parameters:
+ 
+ view       The view to display in the attached window. Must not be nil.
+ 
+ point      The point to which the attached window should be attached. If you 
+            are also specifying a parent window, the point should be in the 
+            coordinate system of that parent window. If you are not specifying 
+            a window, the point should be in the screen's coordinate space.
+            This value is required.
+ 
+ window     The parent window to attach this one to. Note that no actual 
+            relationship is created (particularly, this window is not made 
+            a childWindow of the parent window).
+            Default: nil.
+ 
+ side       The side of the specified point on which to attach this window.
+            Default: MAPositionAutomatic.
+ 
+ distance   How far from the specified point this window should be.
+            Default: 0.
+ */
+
+- (MAAttachedWindow *)initWithView:(NSView *)view           // designated initializer
+                   attachedToPoint:(NSPoint)point 
+                          inWindow:(NSWindow *)window 
+                            onSide:(MAWindowPosition)side 
+                        atDistance:(float)distance;
+- (MAAttachedWindow *)initWithView:(NSView *)view 
+                   attachedToPoint:(NSPoint)point 
+                          inWindow:(NSWindow *)window 
+                        atDistance:(float)distance;
+- (MAAttachedWindow *)initWithView:(NSView *)view 
+                   attachedToPoint:(NSPoint)point 
+                            onSide:(MAWindowPosition)side 
+                        atDistance:(float)distance;
+- (MAAttachedWindow *)initWithView:(NSView *)view 
+                   attachedToPoint:(NSPoint)point 
+                        atDistance:(float)distance;
+- (MAAttachedWindow *)initWithView:(NSView *)view 
+                   attachedToPoint:(NSPoint)point 
+                          inWindow:(NSWindow *)window;
+- (MAAttachedWindow *)initWithView:(NSView *)view 
+                   attachedToPoint:(NSPoint)point 
+                            onSide:(MAWindowPosition)side;
+- (MAAttachedWindow *)initWithView:(NSView *)view 
+                   attachedToPoint:(NSPoint)point;
+
+// Accessor methods
+- (void)setPoint:(NSPoint)point side:(MAWindowPosition)side;
+- (NSColor *)borderColor;
+- (void)setBorderColor:(NSColor *)value;
+- (float)borderWidth;
+- (void)setBorderWidth:(float)value;                   // See note 1 below.
+- (float)viewMargin;
+- (void)setViewMargin:(float)value;                    // See note 2 below.
+- (float)arrowBaseWidth;
+- (void)setArrowBaseWidth:(float)value;                // See note 2 below.
+- (float)arrowHeight;
+- (void)setArrowHeight:(float)value;                   // See note 2 below.
+- (float)hasArrow;
+- (void)setHasArrow:(float)value;
+- (float)cornerRadius;
+- (void)setCornerRadius:(float)value;                  // See note 2 below.
+- (float)drawsRoundCornerBesideArrow;                  // See note 3 below.
+- (void)setDrawsRoundCornerBesideArrow:(float)value;   // See note 2 below.
+- (void)setBackgroundImage:(NSImage *)value;
+- (NSColor *)windowBackgroundColor;                    // See note 4 below.
+- (void)setBackgroundColor:(NSColor *)value;
+
+/*
+ Notes regarding accessor methods:
+ 
+ 1. The border is drawn inside the viewMargin area, expanding inwards; it does not 
+    increase the width/height of the window. You can use the -setBorderWidth: and 
+    -setViewMargin: methods together to achieve the exact look/geometry you want.
+    (viewMargin is the distance between the edge of the view and the window edge.)
+ 
+ 2. The specified setter methods are primarily intended to be used _before_ the window 
+    is first shown. If you use them while the window is already visible, be aware 
+    that they may cause the window to move and/or resize, in order to stay anchored 
+    to the point specified in the initializer. They may also cause the view to move 
+    within the window, in order to remain centered there.
+ 
+    Note that the -setHasArrow: method can safely be used at any time, and will not 
+    cause moving/resizing of the window. This is for convenience, in case you want 
+    to add or remove the arrow in response to user interaction. For example, you 
+    could make the attached window movable by its background, and if the user dragged 
+    it away from its initial point, the arrow could be removed. This would duplicate 
+    how Aperture's attached windows behave.
+ 
+ 3. drawsRoundCornerBesideArrow takes effect when the arrow is being drawn at a corner,
+    i.e. when it's not at one of the four primary compass directions. In this situation, 
+    if drawsRoundCornerBesideArrow is YES (the default), then that corner of the window 
+    will be rounded just like the other three corners, thus the arrow will be inset 
+    slightly from the edge of the window to allow room for the rounded corner. If this 
+    value is NO, the corner beside the arrow will be a square corner, and the other 
+    three corners will be rounded.
+ 
+    This is useful when you want to attach a window very near the edge of another window, 
+    and don't want the attached window's edge to be visually outside the frame of the 
+    parent window.
+ 
+ 4. Note that to retrieve the background color of the window, you should use the 
+    -windowBackgroundColor method, instead of -backgroundColor. This is because we draw 
+    the entire background of the window (rounded path, arrow, etc) in an NSColor pattern 
+    image, and set it as the backgroundColor of the window.
+ */
+
+@end

+ 951 - 0
MAAttachedWindow.m

@@ -0,0 +1,951 @@
+//
+//  MAAttachedWindow.m
+//
+//  Created by Matt Gemmell on 27/09/2007.
+//  Copyright 2007 Magic Aubergine.
+//
+
+#import "MAAttachedWindow.h"
+
+#define MAATTACHEDWINDOW_DEFAULT_BACKGROUND_COLOR [NSColor colorWithCalibratedWhite:0.1 alpha:0.75]
+#define MAATTACHEDWINDOW_DEFAULT_BORDER_COLOR [NSColor whiteColor]
+#define MAATTACHEDWINDOW_SCALE_FACTOR [[NSScreen mainScreen] userSpaceScaleFactor]
+
+@interface MAAttachedWindow (MAPrivateMethods)
+
+// Geometry
+- (void)_updateGeometry;
+- (MAWindowPosition)_bestSideForAutomaticPosition;
+- (float)_arrowInset;
+
+// Drawing
+- (void)_updateBackground;
+- (NSColor *)_backgroundColorPatternImage;
+- (NSBezierPath *)_backgroundPath;
+- (void)_appendArrowToPath:(NSBezierPath *)path;
+- (void)_redisplay;
+
+@end
+
+@implementation MAAttachedWindow
+
+
+#pragma mark Initializers
+
+
+- (MAAttachedWindow *)initWithView:(NSView *)view 
+                   attachedToPoint:(NSPoint)point 
+                          inWindow:(NSWindow *)window 
+                            onSide:(MAWindowPosition)side 
+                        atDistance:(float)distance
+{
+    // Insist on having a valid view.
+    if (!view) {
+        return nil;
+    }
+    
+    // Create dummy initial contentRect for window.
+    NSRect contentRect = NSZeroRect;
+    contentRect.size = [view frame].size;
+    
+    if ((self = [super initWithContentRect:contentRect 
+                                styleMask:NSBorderlessWindowMask 
+                                  backing:NSBackingStoreBuffered 
+                                    defer:NO])) {
+        _view = view;
+        _window = window;
+        _point = point;
+        _side = side;
+        _distance = distance;
+        
+        // Configure window characteristics.
+        [super setBackgroundColor:[NSColor clearColor]];
+        [self setMovableByWindowBackground:NO];
+        [self setExcludedFromWindowsMenu:YES];
+        [self setAlphaValue:1.0];
+        [self setOpaque:NO];
+        [self setHasShadow:YES];
+        [self useOptimizedDrawing:YES];
+        
+        // Set up some sensible defaults for display.
+        _MABackgroundColor = [MAATTACHEDWINDOW_DEFAULT_BACKGROUND_COLOR copy];
+        borderColor = [MAATTACHEDWINDOW_DEFAULT_BORDER_COLOR copy];
+        borderWidth = 2.0;
+        viewMargin = 2.0;
+        arrowBaseWidth = 20.0;
+        arrowHeight = 16.0;
+        hasArrow = YES;
+        cornerRadius = 8.0;
+        drawsRoundCornerBesideArrow = YES;
+        _resizing = NO;
+        
+        // Work out what side to put the window on if it's "automatic".
+        if (_side == MAPositionAutomatic) {
+            _side = [self _bestSideForAutomaticPosition];
+        }
+        
+        // Configure our initial geometry.
+        [self _updateGeometry];
+        
+        // Update the background.
+        [self _updateBackground];
+        
+        // Add view as subview of our contentView.
+        [[self contentView] addSubview:_view];
+        
+        // Subscribe to notifications for when we change size.
+        [[NSNotificationCenter defaultCenter] addObserver:self 
+                                                 selector:@selector(windowDidResize:) 
+                                                     name:NSWindowDidResizeNotification 
+                                                   object:self];
+    }
+    return self;
+}
+
+
+- (MAAttachedWindow *)initWithView:(NSView *)view 
+                   attachedToPoint:(NSPoint)point 
+                          inWindow:(NSWindow *)window 
+                        atDistance:(float)distance
+{
+    return [self initWithView:view attachedToPoint:point 
+                     inWindow:window onSide:MAPositionAutomatic 
+                   atDistance:distance];
+}
+
+
+- (MAAttachedWindow *)initWithView:(NSView *)view 
+                   attachedToPoint:(NSPoint)point 
+                            onSide:(MAWindowPosition)side 
+                        atDistance:(float)distance
+{
+    return [self initWithView:view attachedToPoint:point 
+                     inWindow:nil onSide:side 
+                   atDistance:distance];
+}
+
+
+- (MAAttachedWindow *)initWithView:(NSView *)view 
+                   attachedToPoint:(NSPoint)point 
+                        atDistance:(float)distance
+{
+    return [self initWithView:view attachedToPoint:point 
+                     inWindow:nil onSide:MAPositionAutomatic 
+                   atDistance:distance];
+}
+
+
+- (MAAttachedWindow *)initWithView:(NSView *)view 
+                   attachedToPoint:(NSPoint)point 
+                          inWindow:(NSWindow *)window
+{
+    return [self initWithView:view attachedToPoint:point 
+                     inWindow:window onSide:MAPositionAutomatic 
+                   atDistance:0];
+}
+
+
+- (MAAttachedWindow *)initWithView:(NSView *)view 
+                   attachedToPoint:(NSPoint)point 
+                            onSide:(MAWindowPosition)side
+{
+    return [self initWithView:view attachedToPoint:point 
+                     inWindow:nil onSide:side 
+                   atDistance:0];
+}
+
+
+- (MAAttachedWindow *)initWithView:(NSView *)view 
+                   attachedToPoint:(NSPoint)point
+{
+    return [self initWithView:view attachedToPoint:point 
+                     inWindow:nil onSide:MAPositionAutomatic 
+                   atDistance:0];
+}
+
+
+- (void)dealloc
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+    [borderColor release];
+    [_MABackgroundColor release];
+    
+    [super dealloc];
+}
+
+
+#pragma mark Geometry
+
+
+- (void)_updateGeometry
+{
+    NSRect contentRect = NSZeroRect;
+    contentRect.size = [_view frame].size;
+    
+    // Account for viewMargin.
+    _viewFrame = NSMakeRect(viewMargin * MAATTACHEDWINDOW_SCALE_FACTOR,
+                            viewMargin * MAATTACHEDWINDOW_SCALE_FACTOR,
+                            [_view frame].size.width, [_view frame].size.height);
+    contentRect = NSInsetRect(contentRect, 
+                              -viewMargin * MAATTACHEDWINDOW_SCALE_FACTOR, 
+                              -viewMargin * MAATTACHEDWINDOW_SCALE_FACTOR);
+    
+    // Account for arrowHeight in new window frame.
+    // Note: we always leave room for the arrow, even if it currently set to 
+    // not be shown. This is so it can easily be toggled whilst the window 
+    // is visible, without altering the window's frame origin point.
+    float scaledArrowHeight = arrowHeight * MAATTACHEDWINDOW_SCALE_FACTOR;
+    switch (_side) {
+        case MAPositionLeft:
+        case MAPositionLeftTop:
+        case MAPositionLeftBottom:
+            contentRect.size.width += scaledArrowHeight;
+            break;
+        case MAPositionRight:
+        case MAPositionRightTop:
+        case MAPositionRightBottom:
+            _viewFrame.origin.x += scaledArrowHeight;
+            contentRect.size.width += scaledArrowHeight;
+            break;
+        case MAPositionTop:
+        case MAPositionTopLeft:
+        case MAPositionTopRight:
+            _viewFrame.origin.y += scaledArrowHeight;
+            contentRect.size.height += scaledArrowHeight;
+            break;
+        case MAPositionBottom:
+        case MAPositionBottomLeft:
+        case MAPositionBottomRight:
+            contentRect.size.height += scaledArrowHeight;
+            break;
+        default:
+            break; // won't happen, but this satisfies gcc with -Wall
+    }
+    
+    // Position frame origin appropriately for _side, accounting for arrow-inset.
+    contentRect.origin = (_window) ? [_window convertBaseToScreen:_point] : _point;
+    float arrowInset = [self _arrowInset];
+    float halfWidth = contentRect.size.width / 2.0;
+    float halfHeight = contentRect.size.height / 2.0;
+    switch (_side) {
+        case MAPositionTopLeft:
+            contentRect.origin.x -= contentRect.size.width - arrowInset;
+            break;
+        case MAPositionTop:
+            contentRect.origin.x -= halfWidth;
+            break;
+        case MAPositionTopRight:
+            contentRect.origin.x -= arrowInset;
+            break;
+        case MAPositionBottomLeft:
+            contentRect.origin.y -= contentRect.size.height;
+            contentRect.origin.x -= contentRect.size.width - arrowInset;
+            break;
+        case MAPositionBottom:
+            contentRect.origin.y -= contentRect.size.height;
+            contentRect.origin.x -= halfWidth;
+            break;
+        case MAPositionBottomRight:
+            contentRect.origin.x -= arrowInset;
+            contentRect.origin.y -= contentRect.size.height;
+            break;
+        case MAPositionLeftTop:
+            contentRect.origin.x -= contentRect.size.width;
+            contentRect.origin.y -= arrowInset;
+            break;
+        case MAPositionLeft:
+            contentRect.origin.x -= contentRect.size.width;
+            contentRect.origin.y -= halfHeight;
+            break;
+        case MAPositionLeftBottom:
+            contentRect.origin.x -= contentRect.size.width;
+            contentRect.origin.y -= contentRect.size.height - arrowInset;
+            break;
+        case MAPositionRightTop:
+            contentRect.origin.y -= arrowInset;
+            break;
+        case MAPositionRight:
+            contentRect.origin.y -= halfHeight;
+            break;
+        case MAPositionRightBottom:
+            contentRect.origin.y -= contentRect.size.height - arrowInset;
+            break;
+        default:
+            break; // won't happen, but this satisfies gcc with -Wall
+    }
+    
+    // Account for _distance in new window frame.
+    switch (_side) {
+        case MAPositionLeft:
+        case MAPositionLeftTop:
+        case MAPositionLeftBottom:
+            contentRect.origin.x -= _distance;
+            break;
+        case MAPositionRight:
+        case MAPositionRightTop:
+        case MAPositionRightBottom:
+            contentRect.origin.x += _distance;
+            break;
+        case MAPositionTop:
+        case MAPositionTopLeft:
+        case MAPositionTopRight:
+            contentRect.origin.y += _distance;
+            break;
+        case MAPositionBottom:
+        case MAPositionBottomLeft:
+        case MAPositionBottomRight:
+            contentRect.origin.y -= _distance;
+            break;
+        default:
+            break; // won't happen, but this satisfies gcc with -Wall
+    }
+    
+    // Reconfigure window and view frames appropriately.
+    [self setFrame:contentRect display:NO];
+    [_view setFrame:_viewFrame];
+}
+
+
+- (MAWindowPosition)_bestSideForAutomaticPosition
+{
+    // Get all relevant geometry in screen coordinates.
+    NSRect screenFrame;
+    if (_window && [_window screen]) {
+        screenFrame = [[_window screen] visibleFrame];
+    } else {
+         screenFrame = [[NSScreen mainScreen] visibleFrame];
+    }
+    NSPoint pointOnScreen = (_window) ? [_window convertBaseToScreen:_point] : _point;
+    NSSize viewSize = [_view frame].size;
+    viewSize.width += (viewMargin * MAATTACHEDWINDOW_SCALE_FACTOR) * 2.0;
+    viewSize.height += (viewMargin * MAATTACHEDWINDOW_SCALE_FACTOR) * 2.0;
+    MAWindowPosition side = MAPositionBottom; // By default, position us centered below.
+    float scaledArrowHeight = (arrowHeight * MAATTACHEDWINDOW_SCALE_FACTOR) + _distance;
+    
+    // We'd like to display directly below the specified point, since this gives a 
+    // sense of a relationship between the point and this window. Check there's room.
+    if (pointOnScreen.y - viewSize.height - scaledArrowHeight < NSMinY(screenFrame)) {
+        // We'd go off the bottom of the screen. Try the right.
+        if (pointOnScreen.x + viewSize.width + scaledArrowHeight >= NSMaxX(screenFrame)) {
+            // We'd go off the right of the screen. Try the left.
+            if (pointOnScreen.x - viewSize.width - scaledArrowHeight < NSMinX(screenFrame)) {
+                // We'd go off the left of the screen. Try the top.
+                if (pointOnScreen.y + viewSize.height + scaledArrowHeight < NSMaxY(screenFrame)) {
+                    side = MAPositionTop;
+                }
+            } else {
+                side = MAPositionLeft;
+            }
+        } else {
+            side = MAPositionRight;
+        }
+    }
+    
+    float halfWidth = viewSize.width / 2.0;
+    float halfHeight = viewSize.height / 2.0;
+    
+    NSRect parentFrame = (_window) ? [_window frame] : screenFrame;
+    float arrowInset = [self _arrowInset];
+    
+    // We're currently at a primary side.
+    // Try to avoid going outwith the parent area in the secondary dimension,
+    // by checking to see if an appropriate corner side would be better.
+    switch (side) {
+        case MAPositionBottom:
+        case MAPositionTop:
+            // Check to see if we go beyond the left edge of the parent area.
+            if (pointOnScreen.x - halfWidth < NSMinX(parentFrame)) {
+                // We go beyond the left edge. Try using right position.
+                if (pointOnScreen.x + viewSize.width - arrowInset < NSMaxX(screenFrame)) {
+                    // We'd still be on-screen using right, so use it.
+                    if (side == MAPositionBottom) {
+                        side = MAPositionBottomRight;
+                    } else {
+                        side = MAPositionTopRight;
+                    }
+                }
+            } else if (pointOnScreen.x + halfWidth >= NSMaxX(parentFrame)) {
+                // We go beyond the right edge. Try using left position.
+                if (pointOnScreen.x - viewSize.width + arrowInset >= NSMinX(screenFrame)) {
+                    // We'd still be on-screen using left, so use it.
+                    if (side == MAPositionBottom) {
+                        side = MAPositionBottomLeft;
+                    } else {
+                        side = MAPositionTopLeft;
+                    }
+                }
+            }
+            break;
+        case MAPositionRight:
+        case MAPositionLeft:
+            // Check to see if we go beyond the bottom edge of the parent area.
+            if (pointOnScreen.y - halfHeight < NSMinY(parentFrame)) {
+                // We go beyond the bottom edge. Try using top position.
+                if (pointOnScreen.y + viewSize.height - arrowInset < NSMaxY(screenFrame)) {
+                    // We'd still be on-screen using top, so use it.
+                    if (side == MAPositionRight) {
+                        side = MAPositionRightTop;
+                    } else {
+                        side = MAPositionLeftTop;
+                    }
+                }
+            } else if (pointOnScreen.y + halfHeight >= NSMaxY(parentFrame)) {
+                // We go beyond the top edge. Try using bottom position.
+                if (pointOnScreen.y - viewSize.height + arrowInset >= NSMinY(screenFrame)) {
+                    // We'd still be on-screen using bottom, so use it.
+                    if (side == MAPositionRight) {
+                        side = MAPositionRightBottom;
+                    } else {
+                        side = MAPositionLeftBottom;
+                    }
+                }
+            }
+            break;
+        default:
+            break; // won't happen, but this satisfies gcc with -Wall
+    }
+    
+    return side;
+}
+
+
+- (float)_arrowInset
+{
+    float cornerInset = (drawsRoundCornerBesideArrow) ? cornerRadius : 0;
+    return (cornerInset + (arrowBaseWidth / 2.0)) * MAATTACHEDWINDOW_SCALE_FACTOR;
+}
+
+
+#pragma mark Drawing
+
+
+- (void)_updateBackground
+{
+    // Call NSWindow's implementation of -setBackgroundColor: because we override 
+    // it in this class to let us set the entire background image of the window 
+    // as an NSColor patternImage.
+    NSDisableScreenUpdates();
+    [super setBackgroundColor:[self _backgroundColorPatternImage]];
+    if ([self isVisible]) {
+        [self display];
+        [self invalidateShadow];
+    }
+    NSEnableScreenUpdates();
+}
+
+
+- (NSColor *)_backgroundColorPatternImage
+{
+    NSImage *bg = [[NSImage alloc] initWithSize:[self frame].size];
+    NSRect bgRect = NSZeroRect;
+    bgRect.size = [bg size];
+    
+    [bg lockFocus];
+    NSBezierPath *bgPath = [self _backgroundPath];
+    [NSGraphicsContext saveGraphicsState];
+    [bgPath addClip];
+    
+    // Draw background.
+    [_MABackgroundColor set];
+    [bgPath fill];
+    
+    // Draw border if appropriate.
+    if (borderWidth > 0) {
+        // Double the borderWidth since we're drawing inside the path.
+        [bgPath setLineWidth:(borderWidth * 2.0) * MAATTACHEDWINDOW_SCALE_FACTOR];
+        [borderColor set];
+        [bgPath stroke];
+    }
+    
+    [NSGraphicsContext restoreGraphicsState];
+    [bg unlockFocus];
+    
+    return [NSColor colorWithPatternImage:[bg autorelease]];
+}
+
+
+- (NSBezierPath *)_backgroundPath
+{
+    /*
+     Construct path for window background, taking account of:
+     1. hasArrow
+     2. _side
+     3. drawsRoundCornerBesideArrow
+     4. arrowBaseWidth
+     5. arrowHeight
+     6. cornerRadius
+     */
+    
+    float scaleFactor = MAATTACHEDWINDOW_SCALE_FACTOR;
+    float scaledRadius = cornerRadius * scaleFactor;
+    float scaledArrowWidth = arrowBaseWidth * scaleFactor;
+    float halfArrowWidth = scaledArrowWidth / 2.0;
+    NSRect contentArea = NSInsetRect(_viewFrame,
+                                     -viewMargin * scaleFactor,
+                                     -viewMargin * scaleFactor);
+    float minX = ceilf(NSMinX(contentArea) * scaleFactor + 0.5f);
+	float midX = NSMidX(contentArea) * scaleFactor;
+	float maxX = floorf(NSMaxX(contentArea) * scaleFactor - 0.5f);
+	float minY = ceilf(NSMinY(contentArea) * scaleFactor + 0.5f);
+	float midY = NSMidY(contentArea) * scaleFactor;
+	float maxY = floorf(NSMaxY(contentArea) * scaleFactor - 0.5f);
+	
+    NSBezierPath *path = [NSBezierPath bezierPath];
+    [path setLineJoinStyle:NSRoundLineJoinStyle];
+    
+    // Begin at top-left. This will be either after the rounded corner, or 
+    // at the top-left point if cornerRadius is zero and/or we're drawing 
+    // the arrow at the top-left or left-top without a rounded corner.
+    NSPoint currPt = NSMakePoint(minX, maxY);
+    if (scaledRadius > 0 &&
+        (drawsRoundCornerBesideArrow || 
+            (_side != MAPositionBottomRight && _side != MAPositionRightBottom)) 
+        ) {
+        currPt.x += scaledRadius;
+    }
+    
+    NSPoint endOfLine = NSMakePoint(maxX, maxY);
+    BOOL shouldDrawNextCorner = NO;
+    if (scaledRadius > 0 &&
+        (drawsRoundCornerBesideArrow || 
+         (_side != MAPositionBottomLeft && _side != MAPositionLeftBottom)) 
+        ) {
+        endOfLine.x -= scaledRadius;
+        shouldDrawNextCorner = YES;
+    }
+    
+    [path moveToPoint:currPt];
+    
+    // If arrow should be drawn at top-left point, draw it.
+    if (_side == MAPositionBottomRight) {
+        [self _appendArrowToPath:path];
+    } else if (_side == MAPositionBottom) {
+        // Line to relevant point before arrow.
+        [path lineToPoint:NSMakePoint(midX - halfArrowWidth, maxY)];
+        // Draw arrow.
+        [self _appendArrowToPath:path];
+    } else if (_side == MAPositionBottomLeft) {
+        // Line to relevant point before arrow.
+        [path lineToPoint:NSMakePoint(endOfLine.x - scaledArrowWidth, maxY)];
+        // Draw arrow.
+        [self _appendArrowToPath:path];
+    }
+    
+    // Line to end of this side.
+    [path lineToPoint:endOfLine];
+    
+    // Rounded corner on top-right.
+    if (shouldDrawNextCorner) {
+        [path appendBezierPathWithArcFromPoint:NSMakePoint(maxX, maxY) 
+                                       toPoint:NSMakePoint(maxX, maxY - scaledRadius) 
+                                        radius:scaledRadius];
+    }
+    
+    
+    // Draw the right side, beginning at the top-right.
+    endOfLine = NSMakePoint(maxX, minY);
+    shouldDrawNextCorner = NO;
+    if (scaledRadius > 0 &&
+        (drawsRoundCornerBesideArrow || 
+         (_side != MAPositionTopLeft && _side != MAPositionLeftTop)) 
+        ) {
+        endOfLine.y += scaledRadius;
+        shouldDrawNextCorner = YES;
+    }
+    
+    // If arrow should be drawn at right-top point, draw it.
+    if (_side == MAPositionLeftBottom) {
+        [self _appendArrowToPath:path];
+    } else if (_side == MAPositionLeft) {
+        // Line to relevant point before arrow.
+        [path lineToPoint:NSMakePoint(maxX, midY + halfArrowWidth)];
+        // Draw arrow.
+        [self _appendArrowToPath:path];
+    } else if (_side == MAPositionLeftTop) {
+        // Line to relevant point before arrow.
+        [path lineToPoint:NSMakePoint(maxX, endOfLine.y + scaledArrowWidth)];
+        // Draw arrow.
+        [self _appendArrowToPath:path];
+    }
+    
+    // Line to end of this side.
+    [path lineToPoint:endOfLine];
+    
+    // Rounded corner on bottom-right.
+    if (shouldDrawNextCorner) {
+        [path appendBezierPathWithArcFromPoint:NSMakePoint(maxX, minY) 
+                                       toPoint:NSMakePoint(maxX - scaledRadius, minY) 
+                                        radius:scaledRadius];
+    }
+    
+    
+    // Draw the bottom side, beginning at the bottom-right.
+    endOfLine = NSMakePoint(minX, minY);
+    shouldDrawNextCorner = NO;
+    if (scaledRadius > 0 &&
+        (drawsRoundCornerBesideArrow || 
+         (_side != MAPositionTopRight && _side != MAPositionRightTop)) 
+        ) {
+        endOfLine.x += scaledRadius;
+        shouldDrawNextCorner = YES;
+    }
+    
+    // If arrow should be drawn at bottom-right point, draw it.
+    if (_side == MAPositionTopLeft) {
+        [self _appendArrowToPath:path];
+    } else if (_side == MAPositionTop) {
+        // Line to relevant point before arrow.
+        [path lineToPoint:NSMakePoint(midX + halfArrowWidth, minY)];
+        // Draw arrow.
+        [self _appendArrowToPath:path];
+    } else if (_side == MAPositionTopRight) {
+        // Line to relevant point before arrow.
+        [path lineToPoint:NSMakePoint(endOfLine.x + scaledArrowWidth, minY)];
+        // Draw arrow.
+        [self _appendArrowToPath:path];
+    }
+    
+    // Line to end of this side.
+    [path lineToPoint:endOfLine];
+    
+    // Rounded corner on bottom-left.
+    if (shouldDrawNextCorner) {
+        [path appendBezierPathWithArcFromPoint:NSMakePoint(minX, minY) 
+                                       toPoint:NSMakePoint(minX, minY + scaledRadius) 
+                                        radius:scaledRadius];
+    }
+    
+    
+    // Draw the left side, beginning at the bottom-left.
+    endOfLine = NSMakePoint(minX, maxY);
+    shouldDrawNextCorner = NO;
+    if (scaledRadius > 0 &&
+        (drawsRoundCornerBesideArrow || 
+         (_side != MAPositionRightBottom && _side != MAPositionBottomRight)) 
+        ) {
+        endOfLine.y -= scaledRadius;
+        shouldDrawNextCorner = YES;
+    }
+    
+    // If arrow should be drawn at left-bottom point, draw it.
+    if (_side == MAPositionRightTop) {
+        [self _appendArrowToPath:path];
+    } else if (_side == MAPositionRight) {
+        // Line to relevant point before arrow.
+        [path lineToPoint:NSMakePoint(minX, midY - halfArrowWidth)];
+        // Draw arrow.
+        [self _appendArrowToPath:path];
+    } else if (_side == MAPositionRightBottom) {
+        // Line to relevant point before arrow.
+        [path lineToPoint:NSMakePoint(minX, endOfLine.y - scaledArrowWidth)];
+        // Draw arrow.
+        [self _appendArrowToPath:path];
+    }
+    
+    // Line to end of this side.
+    [path lineToPoint:endOfLine];
+    
+    // Rounded corner on top-left.
+    if (shouldDrawNextCorner) {
+        [path appendBezierPathWithArcFromPoint:NSMakePoint(minX, maxY) 
+                                       toPoint:NSMakePoint(minX + scaledRadius, maxY) 
+                                        radius:scaledRadius];
+    }
+    
+    [path closePath];
+    return path;
+}
+
+
+- (void)_appendArrowToPath:(NSBezierPath *)path
+{
+    if (!hasArrow) {
+        return;
+    }
+    
+    float scaleFactor = MAATTACHEDWINDOW_SCALE_FACTOR;
+    float scaledArrowWidth = arrowBaseWidth * scaleFactor;
+    float halfArrowWidth = scaledArrowWidth / 2.0;
+    float scaledArrowHeight = arrowHeight * scaleFactor;
+    NSPoint currPt = [path currentPoint];
+    NSPoint tipPt = currPt;
+    NSPoint endPt = currPt;
+    
+    // Note: we always build the arrow path in a clockwise direction.
+    switch (_side) {
+        case MAPositionLeft:
+        case MAPositionLeftTop:
+        case MAPositionLeftBottom:
+            // Arrow points towards right. We're starting from the top.
+            tipPt.x += scaledArrowHeight;
+            tipPt.y -= halfArrowWidth;
+            endPt.y -= scaledArrowWidth;
+            break;
+        case MAPositionRight:
+        case MAPositionRightTop:
+        case MAPositionRightBottom:
+            // Arrow points towards left. We're starting from the bottom.
+            tipPt.x -= scaledArrowHeight;
+            tipPt.y += halfArrowWidth;
+            endPt.y += scaledArrowWidth;
+            break;
+        case MAPositionTop:
+        case MAPositionTopLeft:
+        case MAPositionTopRight:
+            // Arrow points towards bottom. We're starting from the right.
+            tipPt.y -= scaledArrowHeight;
+            tipPt.x -= halfArrowWidth;
+            endPt.x -= scaledArrowWidth;
+            break;
+        case MAPositionBottom:
+        case MAPositionBottomLeft:
+        case MAPositionBottomRight:
+            // Arrow points towards top. We're starting from the left.
+            tipPt.y += scaledArrowHeight;
+            tipPt.x += halfArrowWidth;
+            endPt.x += scaledArrowWidth;
+            break;
+        default:
+            break; // won't happen, but this satisfies gcc with -Wall
+    }
+    
+    [path lineToPoint:tipPt];
+    [path lineToPoint:endPt];
+}
+
+
+- (void)_redisplay
+{
+    if (_resizing) {
+        return;
+    }
+    
+    _resizing = YES;
+    NSDisableScreenUpdates();
+    [self _updateGeometry];
+    [self _updateBackground];
+    NSEnableScreenUpdates();
+    _resizing = NO;
+}
+
+
+# pragma mark Window Behaviour
+
+
+- (BOOL)canBecomeMainWindow
+{
+    return NO;
+}
+
+
+- (BOOL)canBecomeKeyWindow
+{
+    return YES;
+}
+
+
+- (BOOL)isExcludedFromWindowsMenu
+{
+    return YES;
+}
+
+
+- (BOOL)validateMenuItem:(NSMenuItem *)item
+{
+    if (_window) {
+        return [_window validateMenuItem:item];
+    }
+    return [super validateMenuItem:item];
+}
+
+
+- (IBAction)performClose:(id)sender
+{
+    if (_window) {
+        [_window performClose:sender];
+    } else {
+        [super performClose:sender];
+    }
+}
+
+
+# pragma mark Notification handlers
+
+
+- (void)windowDidResize:(NSNotification *)note
+{
+    [self _redisplay];
+}
+
+
+#pragma mark Accessors
+
+
+- (void)setPoint:(NSPoint)point side:(MAWindowPosition)side
+{
+	// Thanks to Martin Redington.
+	_point = point;
+	_side = side;
+	NSDisableScreenUpdates();
+	[self _updateGeometry];
+	[self _updateBackground];
+	NSEnableScreenUpdates();
+}
+
+
+- (NSColor *)windowBackgroundColor {
+    return [[_MABackgroundColor retain] autorelease];
+}
+
+
+- (void)setBackgroundColor:(NSColor *)value {
+    if (_MABackgroundColor != value) {
+        [_MABackgroundColor release];
+        _MABackgroundColor = [value copy];
+        
+        [self _updateBackground];
+    }
+}
+
+
+- (NSColor *)borderColor {
+    return [[borderColor retain] autorelease];
+}
+
+
+- (void)setBorderColor:(NSColor *)value {
+    if (borderColor != value) {
+        [borderColor release];
+        borderColor = [value copy];
+        
+        [self _updateBackground];
+    }
+}
+
+
+- (float)borderWidth {
+    return borderWidth;
+}
+
+
+- (void)setBorderWidth:(float)value {
+    if (borderWidth != value) {
+        float maxBorderWidth = viewMargin;
+        if (value <= maxBorderWidth) {
+            borderWidth = value;
+        } else {
+            borderWidth = maxBorderWidth;
+        }
+        
+        [self _updateBackground];
+    }
+}
+
+
+- (float)viewMargin {
+    return viewMargin;
+}
+
+
+- (void)setViewMargin:(float)value {
+    if (viewMargin != value) {
+        viewMargin = MAX(value, 0.0);
+        
+        // Adjust cornerRadius appropriately (which will also adjust arrowBaseWidth).
+        [self setCornerRadius:cornerRadius];
+    }
+}
+
+
+- (float)arrowBaseWidth {
+    return arrowBaseWidth;
+}
+
+
+- (void)setArrowBaseWidth:(float)value {
+    float maxWidth = (MIN(_viewFrame.size.width, _viewFrame.size.height) + 
+                      (viewMargin * 2.0)) - cornerRadius;
+    if (drawsRoundCornerBesideArrow) {
+        maxWidth -= cornerRadius;
+    }
+    if (value <= maxWidth) {
+        arrowBaseWidth = value;
+    } else {
+        arrowBaseWidth = maxWidth;
+    }
+    
+    [self _redisplay];
+}
+
+
+- (float)arrowHeight {
+    return arrowHeight;
+}
+
+
+- (void)setArrowHeight:(float)value {
+    if (arrowHeight != value) {
+        arrowHeight = value;
+        
+        [self _redisplay];
+    }
+}
+
+
+- (float)hasArrow {
+    return hasArrow;
+}
+
+
+- (void)setHasArrow:(float)value {
+    if (hasArrow != value) {
+        hasArrow = value;
+        
+        [self _updateBackground];
+    }
+}
+
+
+- (float)cornerRadius {
+    return cornerRadius;
+}
+
+
+- (void)setCornerRadius:(float)value {
+    float maxRadius = ((MIN(_viewFrame.size.width, _viewFrame.size.height) + 
+                        (viewMargin * 2.0)) - arrowBaseWidth) / 2.0;
+    if (value <= maxRadius) {
+        cornerRadius = value;
+    } else {
+        cornerRadius = maxRadius;
+    }
+    cornerRadius = MAX(cornerRadius, 0.0);
+    
+    // Adjust arrowBaseWidth appropriately.
+    [self setArrowBaseWidth:arrowBaseWidth];
+}
+
+
+- (float)drawsRoundCornerBesideArrow {
+    return drawsRoundCornerBesideArrow;
+}
+
+
+- (void)setDrawsRoundCornerBesideArrow:(float)value {
+    if (drawsRoundCornerBesideArrow != value) {
+        drawsRoundCornerBesideArrow = value;
+        
+        [self _redisplay];
+    }
+}
+
+
+- (void)setBackgroundImage:(NSImage *)value
+{
+    if (value) {
+        [self setBackgroundColor:[NSColor colorWithPatternImage:value]];
+    }
+}
+
+
+@end