Updates primarilly to Template Editor and NovaTools.

This commit is contained in:
Nicholas Shanks 2002-10-04 19:54:05 +00:00
parent 06b207c96d
commit cc7c0f07c7
46 changed files with 970 additions and 224 deletions

View File

@ -29,7 +29,7 @@ With thanks to: For:
// compile options
#if TARGET_API_MAC_CARBON
#define USE_NIBS 1 // toggle this
#define USE_NIBS 0 // toggle this
#else
#define USE_NIBS 0 // leave this set to zero
#endif

View File

@ -1,7 +1,7 @@
#if defined(__MWERKS__) // compiling with CodeWarrior
#include "MacTypes.r"
#else
#if defined(__APPLE_CC__) // compiling with gcc
#include <Carbon/Carbon.r>
#else // compiling with CodeWarrior, __MWERKS__
#include <Carbon.r>
#endif
/*** CARBON RESOURCES ***/

View File

@ -1,7 +1,7 @@
#if defined(__MWERKS__) // compiling with CodeWarrior
#include "MacTypes.r"
#else
#if defined(__APPLE_CC__) // compiling with gcc
#include <Carbon/Carbon.r>
#else // compiling with CodeWarrior, __MWERKS__
#include <Carbon.r>
#endif
/*** APPLE MENU ***/

View File

@ -1,6 +1,6 @@
#import <Cocoa/Cocoa.h>
@interface NSOutlineView (SelectedItems)
@interface NSOutlineView (ResKnifeSelectedItemExtensions)
- (id)selectedItem;
- (NSArray *)selectedItems;

View File

@ -1,8 +1,8 @@
#import "NSOutlineView-SelectedItems.h"
/* The methods in the following catagory were taken from OmniAppKit */
/* The methods in the following catagory were based upon those in OmniAppKit */
@implementation NSOutlineView (SelectedItems)
@implementation NSOutlineView (ResKnifeSelectedItemExtensions)
- (id)selectedItem
{

View File

@ -3,6 +3,8 @@
#import "SizeFormatter.h"
#import "AttributesFormatter.h"
@class Resource;
@interface OutlineViewDelegate : NSObject
{
IBOutlet NSWindow *window;
@ -10,4 +12,8 @@
IBOutlet SizeFormatter *sizeFormatter;
IBOutlet AttributesFormatter *attributesFormatter;
}
int compareResourcesAscending( Resource *r1, Resource *r2, void *context );
int compareResourcesDescending( Resource *r1, Resource *r2, void *context );
@end

View File

@ -1,13 +1,49 @@
#import "OutlineViewDelegate.h"
#import "ResourceNameCell.h"
#import "Resource.h"
#import "ResourceDataSource.h"
#import "ResourceNameCell.h"
#import "ApplicationDelegate.h"
@implementation OutlineViewDelegate
- (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn *)tableColumn
{
NSArray *oldResources = [(ResourceDataSource *)[tableView dataSource] resources];
NSArray *newResources;
NSLog( @"Clicked table column: %@", tableColumn );
// sort the array
if( ![[tableView indicatorImageInTableColumn:tableColumn] isFlipped] )
newResources = [oldResources sortedArrayUsingFunction:compareResourcesAscending context:(void*)[tableColumn identifier]];
else
newResources = [oldResources sortedArrayUsingFunction:compareResourcesDescending context:(void*)[tableColumn identifier]];
// swap new array for old one
[(ResourceDataSource *)[tableView dataSource] setResources:[NSMutableArray arrayWithArray:newResources]];
[tableView reloadData];
}
int compareResourcesAscending( Resource *r1, Resource *r2, void *context )
{
NSString *key = (NSString *)context;
SEL sel = NSSelectorFromString(key);
if( [key isEqualToString:@"name"] || [key isEqualToString:@"type"] )
return [(NSString *)[r1 performSelector:sel] caseInsensitiveCompare: (NSString *)[r2 performSelector:sel]];
else
return [(NSNumber *)[r1 performSelector:sel] compare: (NSNumber *)[r2 performSelector:sel]];
}
int compareResourcesDescending( Resource *r1, Resource *r2, void *context )
{
NSString *key = (NSString *)context;
SEL sel = NSSelectorFromString(key);
if( [key isEqualToString:@"name"] || [key isEqualToString:@"type"] )
return -1 * [(NSString *)[r1 performSelector:sel] caseInsensitiveCompare: (NSString *)[r2 performSelector:sel]];
else
return -1 * [(NSNumber *)[r1 performSelector:sel] compare: (NSNumber *)[r2 performSelector:sel]];
}
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item

View File

@ -130,6 +130,11 @@
/* Accessors */
- (void)touch
{
[self setDirty:YES];
}
- (BOOL)isDirty
{
return dirty;
@ -247,4 +252,11 @@
}
}
/* description */
- (NSString *)description
{
return [NSString stringWithFormat:@"\nName: %@\nType: %@ ID: %@\nModified: %@", name, type, resID, dirty? @"YES":@"NO"];
}
@end

View File

@ -113,7 +113,7 @@ NSString *DataSourceDidRemoveResourceNotification = @"DataSourceDidRemoveResourc
NSEnumerator *enumerator = [resources objectEnumerator];
while( resource = [enumerator nextObject] )
{
if( [[resource resID] isEqualToNumber:resID] && [[resource type] isEqualToString:type] )
if( resID && [[resource resID] isEqualToNumber:resID] && type && [[resource type] isEqualToString:type] )
return resource;
}
return nil;

View File

@ -328,11 +328,14 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
- (IBAction)playSound:(id)sender
{
// bug: Can only cope with one selected item
Resource *resource = [outlineView itemAtRow:[outlineView selectedRow]];
NSSound *sound = [[NSSound alloc] initWithData:[resource data]];
[sound setDelegate:self];
[sound play];
// bug: can only cope with one selected item
NSData *data = [(Resource *)[outlineView itemAtRow:[outlineView selectedRow]] data];
if( data && [data length] != 0 )
{
SndListPtr sndPtr = (SndListPtr) [data bytes];
SndPlay( nil, &sndPtr, false );
}
else NSBeep();
}
- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finished

View File

@ -1,8 +1,6 @@
#import <Foundation/Foundation.h>
@interface SizeFormatter : NSNumberFormatter
{
}
- (NSString *)stringForObjectValue:(id)obj;

View File

@ -4,6 +4,7 @@
@protocol ResKnifeResourceProtocol
- (void)touch;
- (BOOL)isDirty;
- (NSString *)name;
- (void)setName:(NSString *)newName;

View File

@ -2,9 +2,10 @@
@interface Element : NSObject
{
NSString *type;
NSString *label;
union // for resource data only, ignored for templates
NSString *type;
NSString *label;
NSMutableArray *subelements; // elements of a list type have a sub-array of elements
union // for resource data only, ignored for templates
{
NSString *string;
NSNumber *number;
@ -18,6 +19,7 @@
- (NSString *)label;
- (NSString *)type;
- (NSMutableArray *)subelements;
- (unsigned long)typeAsLong;
- (NSString *)string;
- (void)setString:(NSString *)string;

View File

@ -41,6 +41,18 @@
return *(unsigned long *)[type cString];
}
- (NSMutableArray *)subelements;
{
long myType = [self typeAsLong];
if( myType == 'LSTB' || myType == 'LSTC' )
{
if( subelements == nil )
subelements = [[NSMutableArray alloc] init];
}
else subelements = nil;
return subelements;
}
/* DATA ACCESSORS */
- (NSString *)string

View File

@ -0,0 +1,12 @@
{
IBClasses = (
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{
CLASS = TemplateWindowController;
LANGUAGE = ObjC;
OUTLETS = {fieldsMatrix = NSMatrix; };
SUPERCLASS = NSWindowController;
}
);
IBVersion = 1;
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>672 193 356 240 0 0 1600 1002 </string>
<key>IBFramework Version</key>
<string>286.0</string>
<key>IBSystem Version</key>
<string>6D52</string>
</dict>
</plist>

View File

@ -96,9 +96,13 @@
- (void)parseData
{
unsigned long position = 0, loopStart;
unsigned long position = 0;
char *data = (char *) [resource data];
// used for nesting of elements, 'target' is current object to append to, targetStack is a FILO stack of mutable array pointers
NSMutableArray *target = res;
NSMutableArray *targetArray = [NSMutableArray arrayWithObject:res];
// creates an array of elements containing the data in whatever format the template dictates
// array can then simply be manipulated one element at a time, or flattened to save
Element *currentTemplateElement, *resourceElement;
@ -134,7 +138,7 @@
position += 1;
break;
case 'DWRD':
[resourceElement setNumberWithLong:*(int *)(data + position)];
[resourceElement setNumberWithLong:*(short *)(data + position)];
position += 2;
break;
case 'DLNG':
@ -155,34 +159,89 @@
[resourceElement setData:[NSData dataWithBytes:(void *)(data + position) length:4]];
position += 4;
break;
case 'HEXD':
// bug: doesn't check HEXD is the last element
[resourceElement setData:[NSData dataWithBytes:(void *)(data + position) length:([[resource size] intValue] - position)]];
position = [[resource size] intValue];
/* List Counts */
case 'BCNT':
case 'BZCT':
// bug: how big are these various count fields?
[resourceElement setNumberWithLong:*(char *)(data + position)];
position += 1;
break;
case 'OCNT':
case 'ZCNT':
// bug: how big are these various count fields?
[resourceElement setNumberWithLong:*(short *)(data + position)];
position += 2;
break;
case 'LCNT':
case 'LZCT':
// bug: how big are these various count fields?
[resourceElement setNumberWithLong:*(long *)(data + position)];
position += 4;
break;
/* List beginning and end */
case 'LSTB':
case 'LSTC':
target = [resourceElement subelements];
[targetArray addObject:target];
break;
case 'LSTE':
// bug: if there is a LSTE without a preceeding LSTB or LSTC this will crash
[targetArray removeLastObject];
target = [targetArray lastObject];
resourceElement = nil; // relies on element being previously autoreleased to avoid a leak
break;
/* Cxxx, Hxxx or P0xx */
default:
{ unsigned long length = type & 0x00FFFFFF;
NSLog( @"error, Cxxx, Hxxx and P0xx unsupported" );
// bug: should look for Cxxx, Hxxx or P0xx and complain if it's something else (an unknown type)!!
{/* long lengthStr = (type & 0x00FFFFFF) << 8;
unsigned long length = strtoul( (char *) &lengthStr, nil, 10 );
*/ char *lengthStr = (type & 0x00FFFFFF) & (3 << 24);
unsigned long length;
StringToNum(lengthStr, &length);
NSLog( @"error, Cxxx, Hxxx and P0xx unsupported, skipping %d bytes", length );
resourceElement = nil; // relies on element being previously autoreleased to avoid a leak
position += length;
} break;
} // end switch
if( resourceElement ) [res addObject:resourceElement];
if( resourceElement ) [target addObject:resourceElement];
} // end while loop
}
- (void)createUI
{
// iterate through res creating fields
Element *currentResourceElement;
NSEnumerator *enumerator = [res objectEnumerator];
NSLog( @"%d", [res count] );
while( currentResourceElement = [enumerator nextObject] )
{
NSFormCell *newField = [[NSFormCell alloc] initTextCell:[currentResourceElement label]];
[fieldsMatrix addRowWithCells:[NSArray arrayWithObject:[newField autorelease]]];
NSLog( @"%@ added to matrix", [newField description] );
}
[self enumerateElements:res];
NSLog( [fieldsMatrix description] );
[fieldsMatrix setNeedsDisplay];
}
- (void)enumerateElements:(NSMutableArray *)elements
{
// iterate through the array of resource elements, creating fields
Element *currentResourceElement;
NSEnumerator *enumerator = [elements objectEnumerator];
NSLog( @"%d", [elements count] );
while( currentResourceElement = [enumerator nextObject] )
{
// if element is a container, iterate inside it first
if( [currentResourceElement subelements] )
[self enumerateElements:[currentResourceElement subelements]];
else // element is normal
{
NSFormCell *newField = [[NSFormCell alloc] initTextCell:[currentResourceElement label]];
[fieldsMatrix addRowWithCells:[NSArray arrayWithObject:[newField autorelease]]];
NSLog( @"%@ added to matrix", [newField description] );
}
}
}
- (void)resourceDataDidChange:(NSNotification *)notification
{
// ensure it's our resource which got changed (should always be true, we don't register for notifications on other resource objects)
@ -192,7 +251,6 @@
- (void)refreshData:(NSData *)data;
{
#warning Should update data when datachanged notification received
// put data from resource into correct fields
}

View File

@ -1,6 +1,6 @@
#include "Events.h"
#include "HexWindow.h"
#include "Utility.h"
#include "HexUtility.h"
extern globals g;
extern prefs p;
@ -86,7 +86,7 @@ pascal OSStatus CarbonWindowEventHandler( EventHandlerCallRef handler, EventRef
Boolean clickAscii = false; // clicked in ascii rect? - neither means not editing
Plug_WindowRef plugWindow = Host_GetPlugWindowFromWindowRef( window );
HexWindowPtr hexWindow = (HexWindowPtr) Host_GetWindowRefCon( plugWindow );
if( PtInRect( mouse, &hexWindow->hexRect ) ) { clickHex = true; hexWindow->editingHex = true; }
if( PtInRect( mouse, &hexWindow->hexRect ) ) { clickHex = true; hexWindow->editingHex = true; }
if( PtInRect( mouse, &hexWindow->asciiRect ) ) { clickAscii = true; hexWindow->editingHex = false; }
if( clickHex || clickAscii ) error = HandleEditClick( window, event, mouse, (EventModifiers) LoWord(modifiers) );
else error = eventNotHandledErr;

View File

@ -1,7 +1,7 @@
#include "HexWindow.h"
#include "Events.h"
#include "stdio.h"
// #include "strings.h"
#include <stdio.h>
#include <string.h>
extern globals g;
extern prefs p;
@ -303,8 +303,9 @@ OSStatus HexWindow::DrawContent( EventRef event )
if( currentByte < length )
{
// BlockMoveData( *data + currentByte, &ascii, 1 );
hex1 = *(*data + currentByte);
hex2 = *(*data + currentByte);
// hex1 = *(*data + currentByte);
// hex2 = *(*data + currentByte);
ascii = hex1 = hex2 = *(*data + currentByte);
hex1 >>= 4;
hex1 &= 0x0F;
hex2 &= 0x0F;

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,9 @@
#if !TARGET_API_MAC_OS8
#include <Carbon/Carbon.h>
#if defined(__APPLE_CC__) // compiling with gcc
#include <Carbon/Carbon.h>
#else // compiling with CodeWarrior, __MWERKS__
#include <Carbon.h>
#endif
#endif
#ifndef _ResKnife_Plug_

View File

@ -13,8 +13,11 @@
- (void)setData:(NSMutableDictionary *)newData;
- (void)setString:(NSString *)newData forResID:(int)resID;
- (void)parseForString:(NSString *)string sorted:(BOOL)sort;
- (void)parseForString:(NSString *)string withinRange:(NSRange)resIDRange sorted:(BOOL)sort;
- (id)objectValueForResID:(NSNumber *)resID;
- (NSString *)stringValueForResID:(NSNumber *)resID;
+ (NSNumber *)resIDFromStringValue:(NSString *)string;
+ (NSString *)resNameFromStringValue:(NSString *)string;
// NSComboBoxDataSource informal protocol
- (id)comboBox:(NSComboBox *)comboBox objectValueForItemAtIndex:(int)index;

View File

@ -1,5 +1,6 @@
#import "DataSource.h"
#import "ResKnifeResourceProtocol.h"
#import "NSNumber-Range.h"
@implementation DataSource
@ -16,7 +17,7 @@
data = [[NSMutableDictionary alloc] init];
{
id <ResKnifeResourceProtocol> resource;
NSArray *resources = [NSClassFromString(@"Resource") allResourcesOfType:type inDocument:nil];
NSArray *resources = [NSClassFromString(@"Resource") allResourcesOfType:type inDocument:nil]; // nil document will search in ANY open document for the correct resource
NSEnumerator *enumerator = [resources objectEnumerator];
while( resource = [enumerator nextObject] )
[data setObject:[resource name] forKey:[resource resID]];
@ -27,6 +28,7 @@
- (void)dealloc
{
[type release];
[data release];
[parsed release];
[super dealloc];
@ -51,16 +53,22 @@
}
- (void)parseForString:(NSString *)string sorted:(BOOL)sort
{
[self parseForString:string withinRange:NSMakeRange(-32767, 65536) sorted:sort];
}
- (void)parseForString:(NSString *)string withinRange:(NSRange)resIDRange sorted:(BOOL)sort
{
NSNumber *resID;
NSString *trimmedString = [DataSource resNameFromStringValue:string];
NSEnumerator *enumerator = [[data allKeys] objectEnumerator];
[parsed removeAllObjects];
while( resID = [enumerator nextObject] )
{
NSString *value = [data objectForKey:resID];
NSRange range = [value rangeOfString:string options:NSCaseInsensitiveSearch];
if( range.location != NSNotFound || [string isEqualToString:@""] )
[parsed addObject:[NSString stringWithFormat:@"%@ {%@}", value, resID]];
NSRange range = [value rangeOfString:trimmedString options:NSCaseInsensitiveSearch];
if( ((range.location != NSNotFound && range.length != 0) || [trimmedString isEqualToString:@""]) && [resID isBoundedByRange:resIDRange] )
[parsed addObject:[self stringValueForResID:resID]];
}
if( sort ) [parsed sortUsingSelector:@selector(caseInsensitiveCompare:)];
}
@ -72,7 +80,43 @@
- (NSString *)stringValueForResID:(NSNumber *)resID
{
return [NSString stringWithFormat:@"%@ {%@}", [data objectForKey:resID], resID];
if( resID && [data objectForKey:resID] )
return [NSString stringWithFormat:@"%@ {%@}", [data objectForKey:resID], resID];
else if( [resID isEqualToNumber:[NSNumber numberWithInt:-1]] )
return @"";
else if( resID )
return [NSString stringWithFormat:@"{%@}", resID];
return nil;
}
+ (NSNumber *)resIDFromStringValue:(NSString *)string
{
NSRange span, range = NSMakeRange(0,0);
span = [string rangeOfString:@"{" options:NSBackwardsSearch];
if( span.location != NSNotFound ) range.location = span.location +1;
else return [NSNumber numberWithInt:-1];
span = [string rangeOfString:@"}" options:NSBackwardsSearch];
if( span.location != NSNotFound ) range.length = span.location - range.location;
else return [NSNumber numberWithInt:-1];
NS_DURING
NS_VALUERETURN( [[[NSNumber alloc] initWithInt:[[string substringWithRange:range] intValue]] autorelease], NSNumber* );
NS_HANDLER
NS_VALUERETURN( nil, NSNumber* );
NS_ENDHANDLER
}
+ (NSString *)resNameFromStringValue:(NSString *)string
{
NSRange range = [string rangeOfString:@"{" options:NSBackwardsSearch];
if( range.location != NSNotFound )
{
NS_DURING
NS_VALUERETURN( [string substringToIndex:range.location -1], NSString* );
NS_HANDLER
NS_VALUERETURN( nil, NSString* );
NS_ENDHANDLER
}
else return string;
}
/* NSComboBox Informal Prototype Implementation */
@ -89,21 +133,16 @@
/* Combo Box Delegate Methods */
- (void)controlTextDidBeginEditing:(NSNotification *)notification
{
[self parseForString:[[notification object] stringValue] sorted:YES];
[[notification object] reloadData];
}
- (void)controlTextDidChange:(NSNotification *)notification
{
[self parseForString:[[notification object] stringValue] sorted:YES];
[[notification object] reloadData];
}
- (BOOL)control:(NSControl *)control isValidObject:(id)object
{
return [parsed containsObject:object];
}
/* Description */
- (NSString *)description
{
return [NSString stringWithFormat:@"\nType: %@\nData: %@\nParsed Data: %@\n", type, [data description], [parsed description]];
}
@end

View File

@ -1,18 +1,27 @@
#import <Cocoa/Cocoa.h>
#import <Carbon/Carbon.h>
#import "Structs.h"
#import "DataSource.h"
#import "ResKnifePluginProtocol.h"
#import "ResKnifeResourceProtocol.h"
#define localCenter [NSNotificationCenter defaultCenter]
@interface NovaWindowController : NSWindowController <ResKnifePluginProtocol>
{
id <ResKnifeResourceProtocol> resource;
NSUndoManager *undoManager;
// NSNotificationCenter *localCenter;
NSBundle *plugBundle;
DataSource *descriptionDataSource;
DataSource *governmentDataSource;
DataSource *pictureDataSource;
DataSource *planetDataSource;
DataSource *shipDataSource;
DataSource *soundDataSource;
DataSource *spinDataSource;
}
- (void)setResource:(id <ResKnifeResourceProtocol>)newResource;
@ -20,5 +29,14 @@
- (IBAction)toggleResID:(id)sender;
- (void)resourceNameDidChange:(NSNotification *)notification;
- (void)saveSheetDidClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
- (void)invalidValuesSheetDidClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
@end
@interface NovaWindowController (AbstractNovaMethods)
- (NSDictionary *)validateValues;
- (void)saveResource;
@end

View File

@ -12,7 +12,7 @@
id oldSelf = self;
NSData *classData = [[(id <ResKnifeResourceProtocol>)newResource type] dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *className = [[[NSString stringWithCString:[classData bytes] length:[classData length]] capitalizedString] stringByAppendingString:@"WindowController"];
if( [className isEqualToString:@"Yea(R)WindowController"] ) className = @"YearWindowController";
if( [className isEqualToString:@"Yea(R)WindowController"] ) className = @"YearWindowController"; // lossy conversion turns ¨ into (R), so i have to special-case ØŠ¨
self = [[NSClassFromString(className) alloc] initWithResource:newResource];
[oldSelf release];
if( !self ) return nil;
@ -20,6 +20,9 @@
// do global stuff here
resource = [(id)newResource retain];
undoManager = [[NSUndoManager alloc] init];
// localCenter = [[NSNotificationCenter alloc] init];
plugBundle = [NSBundle bundleForClass:[self class]];
// plugBundle = [NSBundle bundleWithIdentifier:@"au.com.sutherland-studios.resknife.novatools"];
// load the window from the nib file and set it's title
[self window]; // implicitly loads nib
@ -35,29 +38,26 @@
- (void)dealloc
{
// [localCenter release];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[(id)resource autorelease];
[undoManager release];
[shipDataSource release];
[shipDataSource release]; // bug: release all data sources
[super dealloc];
}
- (void)windowDidLoad
{
NSBundle *plugBundle = [NSBundle bundleWithIdentifier:@"au.com.sutherland-studios.resknife.novatools"];
/* NSLog( @"path: %@", [[NSBundle mainBundle] pathForAuxiliaryExecutable:@"NovaTools"] );
NSLog( @"path: %@", [[NSBundle mainBundle] pathForResource:@"NovaTools" ofType:nil] );
NSLog( @"path: %@", [[NSBundle mainBundle] pathForResource:@"NovaTools" ofType:nil inDirectory:@"PlugIns"] );
NSLog( @"path: %@", [[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:@"NovaTools.plugin"] );
NSLog( @"path: %@", [[NSBundle bundleWithIdentifier:@"au.com.sutherland-studios.resknife.novatools"] bundlePath] );
*/
[super windowDidLoad];
// create the data sources (here because this is called just before they are applied to the combo boxes)
descriptionDataSource = [[DataSource alloc] initForType:[plugBundle localizedStringForKey:@"desc" value:@"" table:@"Resource Types"]];
governmentDataSource = [[DataSource alloc] initForType:[plugBundle localizedStringForKey:@"govt" value:@"" table:@"Resource Types"]];
pictureDataSource = [[DataSource alloc] initForType:[plugBundle localizedStringForKey:@"PICT" value:@"" table:@"Resource Types"]];
planetDataSource = [[DataSource alloc] initForType:[plugBundle localizedStringForKey:@"spob" value:@"" table:@"Resource Types"]];
shipDataSource = [[DataSource alloc] initForType:[plugBundle localizedStringForKey:@"ship" value:@"" table:@"Resource Types"]];
soundDataSource = [[DataSource alloc] initForType:[plugBundle localizedStringForKey:@"snd" value:@"" table:@"Resource Types"]];
spinDataSource = [[DataSource alloc] initForType:[plugBundle localizedStringForKey:@"spin" value:@"" table:@"Resource Types"]];
// we don't want this notification until we have a window!
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceNameDidChange:) name:ResourceNameDidChangeNotification object:resource];
@ -70,6 +70,40 @@
return undoManager;
}
- (BOOL)windowShouldClose:(id)sender
{
if( [[self window] isDocumentEdited] )
{
NSDictionary *errorValues = [self validateValues];
NSArray *fields = [errorValues allKeys];
NSArray *descriptions = [errorValues allValues];
switch( [errorValues count] )
{
case 0:
NSBeginAlertSheet( @"Do you want to save the changes you made to this resource?", @"Save", @"DonÕt Save", @"Cancel", sender, self, @selector(saveSheetDidClose:returnCode:contextInfo:), nil, nil, @"Your changes will be lost if you don't save them." );
break;
case 1:
NSBeginAlertSheet( @"Invalid values, changes cannot be saved.", @"Cancel", @"Discard Changes", nil, sender, self, @selector(invalidValuesSheetDidClose:returnCode:contextInfo:), nil, nil, @"An invalid value has been given for one of the resource's items. The following field has it's value set incorrectly:\n\n%@: %@", [fields objectAtIndex:0], [descriptions objectAtIndex:0] );
break;
case 2:
NSBeginAlertSheet( @"Invalid values, changes cannot be saved.", @"Cancel", @"Discard Changes", nil, sender, self, @selector(invalidValuesSheetDidClose:returnCode:contextInfo:), nil, nil, @"There are invalid values given for a couple of the resource's items. The following fields have their values set incorrectly:\n\n%@: %@\n%@: %@", [fields objectAtIndex:0], [descriptions objectAtIndex:0], [fields objectAtIndex:1], [descriptions objectAtIndex:1] );
break;
case 3:
NSBeginAlertSheet( @"Invalid values, changes cannot be saved.", @"Cancel", @"Discard Changes", nil, sender, self, @selector(invalidValuesSheetDidClose:returnCode:contextInfo:), nil, nil, @"There are invalid values given for three of the resource's items. The following fields have their values set incorrectly:\n\n%@: %@\n%@: %@\n%@: %@", [fields objectAtIndex:0], [descriptions objectAtIndex:0], [fields objectAtIndex:1], [descriptions objectAtIndex:1], [fields objectAtIndex:2], [descriptions objectAtIndex:2] );
break;
default:
NSBeginAlertSheet( @"Invalid values, changes cannot be saved.", @"Cancel", @"Discard Changes", nil, sender, self, @selector(invalidValuesSheetDidClose:returnCode:contextInfo:), nil, nil, @"There are invalid values given for many of the resource's items. The following fields have their values set incorrectly:\n\n%@: %@\n%@: %@\n%@: %@\nplus others.", [fields objectAtIndex:0], [descriptions objectAtIndex:0], [fields objectAtIndex:1], [descriptions objectAtIndex:1], [fields objectAtIndex:2], [descriptions objectAtIndex:2] );
break;
}
return NO;
}
else return YES;
}
- (void)setResource:(id <ResKnifeResourceProtocol>)newResource
{
id old = resource;
@ -101,4 +135,35 @@
else [[self window] setTitle:prefix];
}
- (void)saveSheetDidClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
switch( returnCode )
{
case NSAlertDefaultReturn: // save
[self saveResource];
[[self window] close];
break;
case NSAlertAlternateReturn: // don't save
[[self window] close];
break;
case NSAlertOtherReturn: // cancel
break;
}
}
- (void)invalidValuesSheetDidClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
switch( returnCode )
{
case NSAlertDefaultReturn: // cancel
break;
case NSAlertAlternateReturn: // discard changes
[[self window] close];
break;
}
}
@end

View File

@ -576,9 +576,9 @@ typedef struct NebuRec
typedef struct BoomRec
{
short FrameAdvance;
short SoundIndex;
short GraphicIndex;
short FrameAdvance; // 100 = normal speed, less is slower, higher faster
short SoundIndex; // 0-63 index, mapping to 300-363 resID
short GraphicIndex; // 0-63 index, mapping to 400-463 resID
} BoomRec;
typedef struct FletRec

View File

@ -1,8 +1,35 @@
#import <Cocoa/Cocoa.h>
#import "NovaWindowController.h"
enum
{
kMinSpinID = 400,
kSpinIDRange = 64,
kMinSoundID = 300,
kSoundIDRange = 64
};
@interface BoomWindowController : NovaWindowController
{
BoomRec *boomRec;
IBOutlet NSImageView *imageWell;
IBOutlet NSComboBox *graphicsField;
IBOutlet NSComboBox *soundField;
IBOutlet NSTextField *frameRateField;
IBOutlet NSButton *soundButton;
IBOutlet NSButton *playButton;
// stuff
NSNumber *image;
NSNumber *sound;
NSNumber *frameRate;
BOOL silent;
}
- (void)update;
- (void)controlTextDidChange:(NSNotification *)notification;
- (IBAction)toggleSilence:(id)sender;
- (IBAction)playSound:(id)sender;
@end

View File

@ -2,12 +2,18 @@
@implementation BoomWindowController
- (id)initWithResource:(id)newResource
- (id)initWithResource:(id <ResKnifeResourceProtocol>)newResource
{
self = [self initWithWindowNibName:@"boom"];
if( !self ) return nil;
boomRec = (BoomRec *)calloc(1,sizeof(BoomRec));
boomRec = (BoomRec *) calloc( 1, sizeof(BoomRec) );
[[newResource data] getBytes:boomRec];
silent = (boomRec->SoundIndex == -1);
if( boomRec->FrameAdvance == 0 ) boomRec->FrameAdvance = 100;
image = [[NSNumber alloc] initWithShort:boomRec->GraphicIndex +400];
sound = [[NSNumber alloc] initWithShort:boomRec->SoundIndex +300 + (silent? 1:0)];
frameRate = [[NSNumber alloc] initWithShort:boomRec->FrameAdvance];
return self;
}
@ -15,7 +21,128 @@
- (void)windowDidLoad
{
[super windowDidLoad];
// set combo box data sources
[graphicsField setDelegate:spinDataSource];
[graphicsField setDataSource:spinDataSource];
[soundField setDelegate:soundDataSource];
[soundField setDataSource:soundDataSource];
// set notifications for ending editing on a combo box
[localCenter addObserver:self selector:@selector(comboBoxWillPopUp:) name:NSComboBoxWillPopUpNotification object:nil];
[localCenter addObserver:self selector:@selector(controlTextDidChange:) name:NSComboBoxWillDismissNotification object:nil];
[localCenter addObserver:self selector:@selector(controlTextDidChange:) name:NSControlTextDidChangeNotification object:nil];
[self update];
[self showWindow:self];
}
- (void)update
{
// graphics
[graphicsField setObjectValue:[spinDataSource stringValueForResID:image]];
// [spinDataSource parseForString:[graphicsField stringValue] withinRange:NSMakeRange(kMinSpinID, kSpinIDRange) sorted:NO];
[frameRateField setObjectValue:frameRate];
// sound
[soundField setObjectValue:[soundDataSource stringValueForResID:sound]];
// [soundDataSource parseForString:[soundField stringValue] withinRange:NSMakeRange(kMinSoundID, kSoundIDRange) sorted:NO];
[soundButton setState:!silent];
[soundField setEnabled:!silent];
[playButton setEnabled:!silent];
// image well
[imageWell setImage:[[[NSImage alloc] initWithData:[(id <ResKnifeResourceProtocol>)[NSClassFromString(@"Resource") resourceOfType:[plugBundle localizedStringForKey:@"spin" value:@"" table:@"Resource Types"] andID:image inDocument:nil] data]] autorelease]];
}
- (void)comboBoxWillPopUp:(NSNotification *)notification
{
id sender = [notification object];
if( sender == graphicsField )
[spinDataSource parseForString:[sender stringValue] withinRange:NSMakeRange(kMinSpinID, kSpinIDRange) sorted:YES];
else if( sender == soundField )
[soundDataSource parseForString:[sender stringValue] withinRange:NSMakeRange(kMinSoundID, kSoundIDRange) sorted:YES];
if( [sender class] == NSClassFromString(@"NSComboBox") )
[sender reloadData];
}
- (void)controlTextDidChange:(NSNotification *)notification
{
id sender = [notification object];
if( sender == graphicsField && [sender stringValue] )
{
id old = image;
image = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![image isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == soundField && [sender stringValue] )
{
id old = sound;
sound = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![sound isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == frameRateField )
{
id old = frameRate;
frameRate = [[NSNumber alloc] initWithInt:[sender intValue]];
if( ![frameRate isEqualToNumber:old] ) [resource touch];
[old release];
}
// hack to simply & easily parse combo boxes
[self comboBoxWillPopUp:notification];
[self setDocumentEdited:[resource isDirty]];
}
- (IBAction)toggleSilence:(id)sender
{
silent = ![soundButton state];
[soundField setEnabled:!silent];
[playButton setEnabled:!silent];
[resource touch];
[self setDocumentEdited:YES];
}
- (IBAction)playSound:(id)sender
{
NSData *data = [(id <ResKnifeResourceProtocol>)[NSClassFromString(@"Resource") resourceOfType:[plugBundle localizedStringForKey:@"snd" value:@"" table:@"Resource Types"] andID:sound inDocument:nil] data];
if( data && [data length] != 0 )
{
SndListPtr sndPtr = (SndListPtr) [data bytes];
SndPlay( nil, &sndPtr, false );
}
else NSBeep();
}
- (NSDictionary *)validateValues
{
NSMutableDictionary *errorValues = [NSMutableDictionary dictionary];
// get current values
boomRec->GraphicIndex = [image shortValue] -400;
boomRec->SoundIndex = [sound shortValue] -300;
boomRec->FrameAdvance = [frameRate shortValue];
if( silent ) boomRec->SoundIndex = -1;
// verify values are valid
if( boomRec->GraphicIndex < 0 || boomRec->GraphicIndex > 63 )
[errorValues setObject:@"must match a spin resource with ID between 400 and 463." forKey:@"Graphics"];
if( boomRec->SoundIndex < -1 || boomRec->SoundIndex > 63 )
[errorValues setObject:@"must match a sound resource with ID between 300 and 363." forKey:@"Sound"];
if( boomRec->FrameAdvance < 1 || boomRec->FrameAdvance > 1000 )
[errorValues setObject:@"cannot be below 0% or above 1000%." forKey:@"Frame Advance"];
// all values fell within acceptable range
return errorValues;
}
- (void)saveResource
{
// save new data into resource structure (should have already been validated, and boomRec filled out correctly)
[resource setData:[NSData dataWithBytes:boomRec length:sizeof(boomRec)]];
}
@end

View File

@ -1,8 +1,17 @@
{
IBClasses = (
{
ACTIONS = {playSound = id; toggleSilence = id; };
CLASS = BoomWindowController;
LANGUAGE = ObjC;
OUTLETS = {
frameRateField = NSTextField;
graphicsField = NSComboBox;
imageWell = NSImageView;
playButton = NSButton;
soundButton = NSButton;
soundField = NSComboBox;
};
SUPERCLASS = NovaWindowController;
},
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },

View File

@ -3,10 +3,14 @@
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>120 159 356 240 0 0 1152 848 </string>
<string>161 150 356 240 0 0 1600 1002 </string>
<key>IBFramework Version</key>
<string>263.2</string>
<string>248.0</string>
<key>IBOpenObjects</key>
<array>
<integer>5</integer>
</array>
<key>IBSystem Version</key>
<string>5Q125</string>
<string>5S66</string>
</dict>
</plist>

Binary file not shown.

View File

@ -1,17 +1,25 @@
#import <Cocoa/Cocoa.h>
#import "NovaWindowController.h"
#define cashField [goodiesForm cellAtIndex:0]
#define killsField [goodiesForm cellAtIndex:1]
#define prefixField [timeForm cellAtIndex:0]
#define suffixField [timeForm cellAtIndex:1]
#define statusField1 [statusForm cellAtIndex:0]
#define statusField2 [statusForm cellAtIndex:1]
#define statusField3 [statusForm cellAtIndex:2]
#define statusField4 [statusForm cellAtIndex:3]
#define cashField [goodiesForm cellAtIndex:0]
#define killsField [goodiesForm cellAtIndex:1]
#define prefixField [timeForm cellAtIndex:0]
#define suffixField [timeForm cellAtIndex:1]
#define statusField1 [statusForm cellAtIndex:0]
#define statusField2 [statusForm cellAtIndex:1]
#define statusField3 [statusForm cellAtIndex:2]
#define statusField4 [statusForm cellAtIndex:3]
#define introDelayField1 [introDelayForm cellAtIndex:0]
#define introDelayField2 [introDelayForm cellAtIndex:1]
#define introDelayField3 [introDelayForm cellAtIndex:2]
#define introDelayField4 [introDelayForm cellAtIndex:3]
#define onStartField [ncbForm cellAtIndex:0]
@interface CharWindowController : NovaWindowController
{
CharRec *charRec;
IBOutlet NSButton *principalCharButton;
IBOutlet NSComboBox *shipField;
IBOutlet NSForm *goodiesForm;
@ -34,6 +42,20 @@
IBOutlet NSComboBox *governmentField3;
IBOutlet NSComboBox *governmentField4;
IBOutlet NSComboBox *introPictField1;
IBOutlet NSComboBox *introPictField2;
IBOutlet NSComboBox *introPictField3;
IBOutlet NSComboBox *introPictField4;
IBOutlet NSForm *introDelayForm;
IBOutlet NSComboBox *introTextField;
IBOutlet NSImageView *introImageView;
IBOutlet NSTextView *introTextView;
IBOutlet NSForm *ncbForm;
// char
BOOL principalChar;
// Initial Goodies
NSNumber *ship;
NSNumber *cash;
@ -59,10 +81,27 @@
NSNumber *government2;
NSNumber *government3;
NSNumber *government4;
// Introduction
NSNumber *introText;
NSNumber *introPict1;
NSNumber *introPict2;
NSNumber *introPict3;
NSNumber *introPict4;
NSNumber *introDelay1;
NSNumber *introDelay2;
NSNumber *introDelay3;
NSNumber *introDelay4;
NSTimer *introPictTimer;
// Nova Control Bits
NSString *onStart;
}
- (void)update;
- (IBAction)editDate:(id)sender;
- (IBAction)stepDate:(id)sender;
- (void)comboBoxWillPopUp:(NSNotification *)notification;
- (void)controlTextDidChange:(NSNotification *)notification;
@end

View File

@ -2,47 +2,57 @@
@implementation CharWindowController
- (id)initWithResource:(id)newResource
- (id)initWithResource:(id <ResKnifeResourceProtocol>)newResource
{
self = [self initWithWindowNibName:@"char"];
if( !self ) return nil;
// load data from resource
ship = [[NSNumber alloc] initWithShort:128];
cash = [[NSNumber alloc] initWithLong:10000];
kills = [[NSNumber alloc] initWithUnsignedLong:0];
date = [[NSCalendarDate date] retain];
prefix = [[NSString alloc] init];
suffix = [[NSString alloc] init];
start1 = [[NSNumber alloc] initWithShort:128];
start2 = [[NSNumber alloc] initWithShort:129];
start3 = [[NSNumber alloc] initWithShort:130];
start4 = [[NSNumber alloc] initWithShort:131];
status1 = [[NSNumber alloc] initWithShort:0];
status2 = [[NSNumber alloc] initWithShort:0];
status3 = [[NSNumber alloc] initWithShort:0];
status4 = [[NSNumber alloc] initWithShort:0];
government1 = [[NSNumber alloc] initWithShort:128];
government2 = [[NSNumber alloc] initWithShort:129];
government3 = [[NSNumber alloc] initWithShort:130];
government4 = [[NSNumber alloc] initWithShort:131];
charRec = (CharRec *) calloc( 1, sizeof(CharRec) );
[[newResource data] getBytes:charRec];
principalChar = charRec->Flags & 0x0001;
ship = [[NSNumber alloc] initWithShort:charRec->startShipType]; // resID
cash = [[NSNumber alloc] initWithLong:charRec->startCash];
kills = [[NSNumber alloc] initWithShort:charRec->startKills];
date = [[NSCalendarDate alloc] initWithYear:charRec->startYear month:charRec->startMonth day:charRec->startDay hour:0 minute:0 second:0 timeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
prefix = [[NSString alloc] initWithCString:charRec->Prefix length:16];