Added save dialog to Hex Editor and finished Boom & Char Nova Tools

This commit is contained in:
Nicholas Shanks 2002-12-31 19:06:40 +00:00
parent a484060e30
commit 9f6f97977b
40 changed files with 867 additions and 270 deletions

View File

@ -667,7 +667,7 @@ pascal OSStatus CarbonEventUpdateMenus( EventHandlerCallRef callRef, EventRef ev
{
#pragma unused( callRef, event, userData )
OSStatus error = eventNotHandledErr;
Boolean fileOpen = (Boolean) FrontNonFloatingWindow();
Boolean fileOpen = (Boolean) (FrontNonFloatingWindow() != NULL);
// application menu (passing null causes all menus to be searched)
EnableCommand( null, kMenuCommandAbout, true );
@ -1046,6 +1046,7 @@ OSStatus ShowAboutBox( void )
SetRect( &creationBounds, 0, 0, 300, 300 );
OffsetRect( &creationBounds, 50, 50 );
OSStatus error = CreateNewWindow( kDocumentWindowClass, kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute, &creationBounds, &window );
if( error ) return error;
ControlRef picControl;
ControlButtonContentInfo content;

View File

@ -8,7 +8,7 @@ extern globals g;
/*** CREATOR ***/
EditorWindow::EditorWindow( FileWindowPtr ownerFile, ResourceObjectPtr targetResource, WindowRef inputWindow ) : PlugWindow( ownerFile )
{
OSStatus error = noErr;
// OSStatus error = noErr;
// set default variables
window = inputWindow;

View File

@ -369,7 +369,7 @@ pascal OSStatus FileWindowEventHandler( EventHandlerCallRef callRef, EventRef ev
pascal OSStatus FileWindowUpdateMenus( EventHandlerCallRef callRef, EventRef event, void *userData )
{
#pragma unused( callRef, event )
OSStatus error = eventNotHandledErr;
// OSStatus error = eventNotHandledErr;
// get file window
FileWindowPtr file = (FileWindowPtr) userData;
@ -1602,7 +1602,7 @@ OSStatus FileWindow::OpenResource( DataBrowserItemID itemID, MenuCommand command
#pragma unused( command )
// get opened resource
OSStatus error = noErr;
Boolean stop = false;
// Boolean stop = false;
ResourceObjectPtr resource = GetResource( itemID );
// check for null resource

View File

@ -200,10 +200,10 @@ OSStatus FileWindow::DisplayModelessAskSaveChangesDialog( void )
{
OSStatus error;
NavEventUPP eventProc = NewNavEventUPP( ModelessAskSaveChangesHandler );
NavPreviewUPP previewProc = null;
/* NavPreviewUPP previewProc = null;
NavObjectFilterUPP filterProc = null;
NavTypeListHandle typeList = null;
NavAskSaveChangesAction action = g.quitting? kNavSaveChangesQuittingApplication : kNavSaveChangesClosingDocument;
*/ NavAskSaveChangesAction action = g.quitting? kNavSaveChangesQuittingApplication : kNavSaveChangesClosingDocument;
NavDialogCreationOptions options;
error = NavGetDefaultDialogCreationOptions( &options );
options.parentWindow = window;
@ -438,7 +438,7 @@ pascal void ModelessAskSaveChangesHandler( const NavEventCallbackMessage callBac
pascal void ModelessPutFileHandler( const NavEventCallbackMessage callBackSelector, NavCBRecPtr cbRecord, NavCallBackUserData callBackUD )
{
OSStatus error = noErr;
FileWindowPtr file = (FileWindowPtr) callBackUD;
// FileWindowPtr file = (FileWindowPtr) callBackUD;
switch( callBackSelector )
{
case kNavCBUserAction:
@ -464,7 +464,7 @@ pascal void ModelessPutFileHandler( const NavEventCallbackMessage callBackSelect
pascal void ModelessAskDiscardChangesHandler( const NavEventCallbackMessage callBackSelector, NavCBRecPtr cbRecord, NavCallBackUserData callBackUD )
{
OSStatus error = noErr;
FileWindowPtr file = (FileWindowPtr) callBackUD;
// FileWindowPtr file = (FileWindowPtr) callBackUD;
switch( callBackSelector )
{
case kNavCBUserAction:

View File

@ -55,7 +55,7 @@ Plug_PlugInRef Host_GetPlugRef( WindowRef window )
Plug_ResourceRef Host_GetResource( ResType type, SInt32 resID, Plug_ResourceRef sameFileAsResource )
{
FilWindowPtr file;
// FileWindowPtr file;
if( sameFileAsResource != NULL )
{
// file = ((ResourceObjectPtr) sameFileAsResource)->file;

View File

@ -25,85 +25,89 @@ InspectorWindow::InspectorWindow( void )
SetRect( &creationBounds, 0, 0, kInspectorWindowWidth, kInspectorWindowHeight );
OffsetRect( &creationBounds, 520, 45 );
OSStatus error = CreateNewWindow( kFloatingWindowClass, kWindowStandardFloatingAttributes | kWindowStandardHandlerAttribute, &creationBounds, &window );
GetIndString( windowName, kWindowNameStrings, kStringInspectorWindowName );
SetWindowTitle( window, windowName );
SetWindowKind( window, kInspectorWindowKind );
SetThemeWindowBackground( window, kThemeBrushUtilityWindowBackgroundActive, false );
// install window event handler
EventHandlerRef ref = null;
EventHandlerUPP eventHandler = NewEventHandlerUPP( CloseInspectorWindow );
EventTypeSpec events[] = { { kEventClassWindow, kEventWindowClose } };
InstallWindowEventHandler( window, eventHandler, GetEventTypeCount(events), (EventTypeSpec *) &events, this, &ref );
// create root control
Rect bounds;
if( g.systemVersion < kMacOSX )
if( !error )
{
ControlRef root;
CreateRootControl( window, &root );
GetIndString( windowName, kWindowNameStrings, kStringInspectorWindowName );
SetWindowTitle( window, windowName );
SetWindowKind( window, kInspectorWindowKind );
SetThemeWindowBackground( window, kThemeBrushUtilityWindowBackgroundActive, false );
// install window event handler
EventHandlerRef ref = null;
EventHandlerUPP eventHandler = NewEventHandlerUPP( CloseInspectorWindow );
EventTypeSpec events[] = { { kEventClassWindow, kEventWindowClose } };
InstallWindowEventHandler( window, eventHandler, GetEventTypeCount(events), (EventTypeSpec *) &events, this, &ref );
// create root control
Rect bounds;
if( g.systemVersion < kMacOSX )
{
ControlRef root;
CreateRootControl( window, &root );
}
// create image well
ControlRef imageWell;
ControlButtonContentInfo content;
content.contentType = kControlNoContent;
SetRect( &bounds, 0, 0, 44, 44 );
OffsetRect( &bounds, 8, 8 );
CreateImageWellControl( window, &bounds, &content, &imageWell );
// create static text controls
Rect windowRect;
ControlRef name, type, id;
ControlFontStyleRec fontStyle;
fontStyle.flags = kControlUseFontMask + kControlUseJustMask;
fontStyle.font = kControlFontSmallSystemFont;
fontStyle.just = teJustLeft;
GetWindowPortBounds( window, &windowRect );
SetRect( &bounds, windowRect.left +60, windowRect.top +8, windowRect.right - windowRect.left -8, windowRect.top +36 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &name );
fontStyle.font = kControlFontSmallBoldSystemFont;
SetRect( &bounds, windowRect.left +60, windowRect.top +38, windowRect.right - windowRect.left -70, windowRect.top +52 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &type );
SetRect( &bounds, windowRect.right - windowRect.left -70, windowRect.top +38, windowRect.right - windowRect.left -8, windowRect.top +52 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &id );
// create group control
ControlRef group;
GetWindowPortBounds( window, &bounds );
InsetRect( &bounds, 8, 8 );
bounds.top += kInspectorHeaderHeight;
CreateGroupBoxControl( window, &bounds, CFSTR("Attributes"), true, &group );
// create checkboxes
ControlRef changedBox, preloadBox, protectedBox,
lockedBox, purgeableBox, sysHeapBox;
InsetRect( &bounds, 4, 4 );
bounds.top = bounds.bottom - kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("System Heap"), kControlCheckBoxUncheckedValue, true, &sysHeapBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Purgeable"), kControlCheckBoxUncheckedValue, true, &purgeableBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Locked"), kControlCheckBoxUncheckedValue, true, &lockedBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Protected"), kControlCheckBoxUncheckedValue, true, &protectedBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Preload"), kControlCheckBoxUncheckedValue, true, &preloadBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Changed"), kControlCheckBoxUncheckedValue, true, &changedBox );
// embed controls
EmbedControl( changedBox, group );
EmbedControl( preloadBox, group );
EmbedControl( protectedBox, group );
EmbedControl( lockedBox, group );
EmbedControl( purgeableBox, group );
EmbedControl( sysHeapBox, group );
}
// create image well
ControlRef imageWell;
ControlButtonContentInfo content;
content.contentType = kControlNoContent;
SetRect( &bounds, 0, 0, 44, 44 );
OffsetRect( &bounds, 8, 8 );
CreateImageWellControl( window, &bounds, &content, &imageWell );
// create static text controls
Rect windowRect;
ControlRef name, type, id;
ControlFontStyleRec fontStyle;
fontStyle.flags = kControlUseFontMask + kControlUseJustMask;
fontStyle.font = kControlFontSmallSystemFont;
fontStyle.just = teJustLeft;
GetWindowPortBounds( window, &windowRect );
SetRect( &bounds, windowRect.left +60, windowRect.top +8, windowRect.right - windowRect.left -8, windowRect.top +36 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &name );
fontStyle.font = kControlFontSmallBoldSystemFont;
SetRect( &bounds, windowRect.left +60, windowRect.top +38, windowRect.right - windowRect.left -70, windowRect.top +52 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &type );
SetRect( &bounds, windowRect.right - windowRect.left -70, windowRect.top +38, windowRect.right - windowRect.left -8, windowRect.top +52 );
CreateStaticTextControl( window, &bounds, CFSTR(""), &fontStyle, &id );
// create group control
ControlRef group;
GetWindowPortBounds( window, &bounds );
InsetRect( &bounds, 8, 8 );
bounds.top += kInspectorHeaderHeight;
CreateGroupBoxControl( window, &bounds, CFSTR("Attributes"), true, &group );
// create checkboxes
ControlRef changedBox, preloadBox, protectedBox,
lockedBox, purgeableBox, sysHeapBox;
InsetRect( &bounds, 4, 4 );
bounds.top = bounds.bottom - kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("System Heap"), kControlCheckBoxUncheckedValue, true, &sysHeapBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Purgeable"), kControlCheckBoxUncheckedValue, true, &purgeableBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Locked"), kControlCheckBoxUncheckedValue, true, &lockedBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Protected"), kControlCheckBoxUncheckedValue, true, &protectedBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Preload"), kControlCheckBoxUncheckedValue, true, &preloadBox );
bounds.top -= kControlCheckBoxHeight;
bounds.bottom -= kControlCheckBoxHeight;
CreateCheckBoxControl( window, &bounds, CFSTR("Changed"), kControlCheckBoxUncheckedValue, true, &changedBox );
// embed controls
EmbedControl( changedBox, group );
EmbedControl( preloadBox, group );
EmbedControl( protectedBox, group );
EmbedControl( lockedBox, group );
EmbedControl( purgeableBox, group );
EmbedControl( sysHeapBox, group );
else window = NULL;
#else
if( g.useAppearance && g.systemVersion >= kMacOS8 )
window = GetNewCWindow( kFileWindow8, null, kFirstWindowOfClass );
@ -111,10 +115,14 @@ InspectorWindow::InspectorWindow( void )
window = GetNewCWindow( kFileWindow7, null, kFirstWindowOfClass );
#endif
// update and show window
Update();
ShowWindow( window );
g.inspector = this;
if( window )
{
// update and show window
Update();
ShowWindow( window );
g.inspector = this;
}
else g.inspector = NULL;
}
/*** DESTRUCTOR ***/

View File

@ -5,7 +5,7 @@
- (FSRef *)createFSRef
{
FSRef *fsRef = NULL;
OSStatus error = FSPathMakeRef( [self fileSystemRepresentation], &fsRef, NULL );
OSStatus error = FSPathMakeRef( [self fileSystemRepresentation], fsRef, NULL );
if( error == noErr )
return fsRef;
return NULL;
@ -15,10 +15,10 @@
{
FSRef *fsRef = NULL;
FSSpec *fsSpec = NULL;
OSStatus error = FSPathMakeRef( [self fileSystemRepresentation], &fsRef, NULL );
OSStatus error = FSPathMakeRef( [self fileSystemRepresentation], fsRef, NULL );
if( error == noErr )
{
error = FSGetCatalogInfo( &fsRef, kFSCatInfoNone, NULL, NULL, fsSpec, NULL );
error = FSGetCatalogInfo( fsRef, kFSCatInfoNone, NULL, NULL, fsSpec, NULL );
if( error == noErr )
return fsSpec;
}

View File

@ -1,7 +1,7 @@
#import <Foundation/Foundation.h>
#import "ResKnifeResourceProtocol.h"
@interface Resource : NSObject <NSCoding, ResKnifeResourceProtocol>
@interface Resource : NSObject <NSCopying, NSCoding, ResKnifeResourceProtocol>
{
@private
// flags

View File

@ -130,6 +130,12 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
[super dealloc];
}
- (id)copyWithZone:(NSZone *)zone
{
Resource *copy = [[Resource alloc] initWithType:type andID:resID withName:name andAttributes:attributes data:[data copy]];
return copy;
}
/* Accessors */
- (void)touch
@ -284,7 +290,7 @@ NSString *RKResourcePboardType = @"RKResourcePboardType";
- (NSString *)description
{
return [NSString stringWithFormat:@"\nName: %@\nType: %@ ID: %@\nModified: %@", name, type, resID, dirty? @"YES":@"NO"];
return [NSString stringWithFormat:@"\n%@\nName: %@\nType: %@ ID: %@\nSize: %d Modified: %@", [super description], name, type, resID, [data length], dirty? @"YES":@"NO"];
}
@end

View File

@ -310,10 +310,11 @@ static NSString *RKShowInfoItemIdentifier = @"com.nickshanks.resknife.toolbar.sh
NSBundle *templateEditor = [NSBundle bundleWithPath:[[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:@"Template Editor.plugin"]];
// bug: this checks EVERY DOCUMENT for template resources (might not be desired)
// bug: it doesn't, however, check the application's resource map for a matching template!
Resource *tmpl = [Resource resourceOfType:@"TMPL" withName:[resource type] inDocument:nil];
// open the resources, passing in the template to use
if( tmpl && [[templateEditor principalClass] respondsToSelector:@selector(initWithResources:)] )
if( tmpl /*&& [[templateEditor principalClass] respondsToSelector:@selector(initWithResources:)]*/ )
{
// bug: I alloc a plug instance here, but have no idea where I should dealloc it, perhaps the plug ought to call [self autorelease] when it's last window is closed?
// update: doug says window controllers automatically release themselves when their window is closed.

View File

@ -124,7 +124,7 @@
// get the superclass to draw the text stuff
[super drawWithFrame:cellFrame inView:controlView];
}
/*
- (NSSize)cellSize
{
NSSize cellSize = [super cellSize];
@ -132,5 +132,5 @@
cellSize.width += (image? [image size].width:0) + 3;
return cellSize;
}
*/
@end

View File

@ -3,9 +3,9 @@
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>681 234 356 240 0 0 1600 1002 </string>
<string>366 155 356 240 0 0 1024 746 </string>
<key>IBFramework Version</key>
<string>286.0</string>
<string>283.0</string>
<key>IBGroupedObjects</key>
<dict>
<key>0</key>
@ -26,6 +26,6 @@
<integer>7</integer>
</array>
<key>IBSystem Version</key>
<string>6F21</string>
<string>6G30</string>
</dict>
</plist>

View File

@ -5,7 +5,7 @@
/* FORM DELEGATION METHOD */
- (void)controlTextDidEndEditing:(NSNotification *)aNotification
- (void)controlTextDidEndEditing:(NSNotification *)notification
{
[self updateStrings];
}
@ -23,6 +23,16 @@
- (IBAction)showFindSheet:(id)sender
{
// load window so I can play with boxes
[self window];
// enable/disable boxes
[searchSelectionOnlyBox setEnabled:([(NSTextView *)[[sender window] firstResponder] rangeForUserTextChange].length != 0)];
// set inital vales
if( ![searchSelectionOnlyBox isEnabled] ) [searchSelectionOnlyBox setIntValue:0];
// show sheet
[NSApp beginSheet:[self window] modalForWindow:[sender window] modalDelegate:self didEndSelector:NULL contextInfo:nil];
}

View File

@ -5,6 +5,7 @@
@interface HexTextView : NSTextView
{
}
- (IBAction)clear:(id)sender;
- (IBAction)pasteAsASCII:(id)sender;
- (IBAction)pasteAsHex:(id)sender;
- (IBAction)pasteAsUnicode:(id)sender;

View File

@ -444,7 +444,7 @@ static NSRange draggedRange;
[newData replaceBytesInRange:range withBytes:[newBytes bytes] length:[newBytes length]];
[[(HexWindowController *)[[self window] windowController] resource] setData:newData];
[self setSelectedRange:NSMakeRange(range.location + [newBytes length], 0)];
[[self window] setDocumentEdited:YES];
// [[self window] setDocumentEdited:YES]; // moved to window controller's -resourceDataDidChange: notification method
// record undo with new data object
[[[[self window] undoManager] prepareWithInvocationTarget:self] editData:newData replaceBytesInRange:newRange withData:oldBytes];

View File

@ -21,6 +21,8 @@
NSUndoManager *undoManager;
id <ResKnifeResourceProtocol> resource;
id <ResKnifeResourceProtocol> backup;
BOOL liveEdit;
int bytesPerRow;
}
@ -30,10 +32,16 @@
// show find sheet
- (IBAction)showFind:(id)sender;
// save sheet methods
- (void)saveSheetDidClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
- (void)saveResource;
- (void)revertResource;
// normal methods
- (void)viewDidScroll:(NSNotification *)notification;
- (void)resourceNameDidChange:(NSNotification *)notification;
- (void)resourceDataDidChange:(NSNotification *)notification;
- (void)resourceWasSaved:(NSNotification *)notification;
- (void)refreshData:(NSData *)data;
// accessors

View File

@ -11,7 +11,17 @@
// one instance of your principal class will be created for every resource the user wants to edit (similar to Windows apps)
undoManager = [[NSUndoManager alloc] init];
resource = [newResource retain];
liveEdit = NO;
if( liveEdit )
{
resource = [newResource retain];
backup = [newResource copy];
}
else
{
resource = [newResource copy];
backup = [newResource retain];
}
bytesPerRow = 16;
// load the window from the nib file and set it's title
@ -30,7 +40,7 @@
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[(id)resource autorelease];
[(id)resource release];
[super dealloc];
}
@ -59,6 +69,8 @@
// we don't want this notification until we have a window! (Only register for notifications on the resource we're editing)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceNameDidChange:) name:ResourceNameDidChangeNotification object:resource];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceDataDidChange:) name:ResourceDataDidChangeNotification object:resource];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceWasSaved:) name:ResourceWasSavedNotification object:resource];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resourceWasSaved:) name:ResourceWasSavedNotification object:backup];
// put other notifications here too, just for togetherness
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidScroll:) name:NSViewBoundsDidChangeNotification object:[[offset enclosingScrollView] contentView]];
@ -105,11 +117,55 @@
[pasteItem setKeyEquivalentModifierMask:NSCommandKeyMask];
}
/*
- (BOOL)windowShouldClose:(NSWindow *)sender
- (BOOL)windowShouldClose:(id)sender
{
return [sender isDocumentEdited];
}*/
if( [[self window] isDocumentEdited] )
{
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." );
return NO;
}
else return YES;
}
- (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 revertResource];
[[self window] close];
break;
case NSAlertOtherReturn: // cancel
break;
}
}
- (void)saveResource
{
if( liveEdit )
{
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillBeSavedNotification object:resource];
[backup setData:[resource data]];
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWasSavedNotification object:resource];
}
else
{
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWillBeSavedNotification object:backup];
[backup setData:[resource data]];
[[NSNotificationCenter defaultCenter] postNotificationName:ResourceWasSavedNotification object:backup];
}
}
- (void)revertResource
{
[resource setData:[backup data]];
}
- (IBAction)showFind:(id)sender
{
@ -127,7 +183,7 @@
NSClipView *asciiClip = [[ascii enclosingScrollView] contentView];
// due to a bug in -[NSView setPostsBoundsChangedNotifications:] (it basically doesn't work), I am having to work around it by removing myself from the notification center and restoring things later on!
// update, Apple say this isn't their bug.
// update, Apple say this isn't their bug. Yeah, right!
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSViewBoundsDidChangeNotification object:nil];
// when a view scrolls, update the other two
@ -169,7 +225,36 @@
{
// ensure it's our resource which got changed (should always be true, we don't register for other resource notifications)
if( [notification object] == (id)resource )
{
[self refreshData:[resource data]];
[self setDocumentEdited:YES];
}
}
- (void)resourceWasSaved:(NSNotification *)notification
{
NSLog( @"%@; %@; %@", [notification object], resource, backup );
if( [notification object] == (id)resource )
{
// if resource gets saved, liveEdit is true and this resource is saving
[backup setData:[resource data]];
[self setDocumentEdited:NO];
}
else if( [notification object] == (id)backup && !liveEdit )
{
// backup will get saved by this resource if liveEdit is false, rather than the 'resource' variable
// but really the data to preserve is in the resource variable
[backup setData:[resource data]];
// [self refreshData:[resource data]];
[self setDocumentEdited:NO];
}
else if( [notification object] == (id)backup )
{
// backup will get saved by another editor too if liveEdit is false
[resource setData:[backup data]];
// [self refreshData:[resource data]];
[self setDocumentEdited:NO];
}
}
- (void)refreshData:(NSData *)data;

View File

@ -12,10 +12,12 @@ NSString *ResourceTypeWillChangeNotification = @"ResourceTypeWillChangeNotifica
NSString *ResourceIDWillChangeNotification = @"ResourceIDWillChangeNotification";
NSString *ResourceAttributesWillChangeNotification = @"ResourceAttributesWillChangeNotification";
NSString *ResourceDataWillChangeNotification = @"ResourceDataWillChangeNotification";
NSString *ResourceWillBeSavedNotification = @"ResourceWillBeSavedNotification";
NSString *ResourceNameDidChangeNotification = @"ResourceNameDidChangeNotification";
NSString *ResourceTypeDidChangeNotification = @"ResourceTypeDidChangeNotification";
NSString *ResourceIDDidChangeNotification = @"ResourceIDDidChangeNotification";
NSString *ResourceAttributesDidChangeNotification = @"ResourceAttributesDidChangeNotification";
NSString *ResourceDataDidChangeNotification = @"ResourceDataDidChangeNotification";
NSString *ResourceDidChangeNotification = @"ResourceDidChangeNotification";
NSString *ResourceDidChangeNotification = @"ResourceDidChangeNotification";
NSString *ResourceWasSavedNotification = @"ResourceWasSavedNotification";

View File

@ -39,10 +39,12 @@ extern NSString *ResourceTypeWillChangeNotification;
extern NSString *ResourceIDWillChangeNotification;
extern NSString *ResourceAttributesWillChangeNotification;
extern NSString *ResourceDataWillChangeNotification;
extern NSString *ResourceWillBeSavedNotification;
extern NSString *ResourceNameDidChangeNotification;
extern NSString *ResourceTypeDidChangeNotification;
extern NSString *ResourceIDDidChangeNotification;
extern NSString *ResourceAttributesDidChangeNotification;
extern NSString *ResourceDataDidChangeNotification;
extern NSString *ResourceDidChangeNotification;
extern NSString *ResourceDidChangeNotification;
extern NSString *ResourceWasSavedNotification;

View File

@ -4,8 +4,7 @@
{
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
union // for resource arrays only, ignored for TMPL arrays
{
NSString *string;
NSNumber *number;
@ -19,7 +18,6 @@
- (NSString *)label;
- (NSString *)type;
- (NSMutableArray *)subelements;
- (unsigned long)typeAsLong;
- (NSString *)string;
- (void)setString:(NSString *)string;

View File

@ -20,7 +20,7 @@
- (id)copy
{
Element *element = [[Element alloc] initWithType:type andLabel:label];
// copy other stuff here
// bug: copy other stuff here
return element;
}
@ -40,7 +40,7 @@
{
return *(unsigned long *)[type cString];
}
/*
- (NSMutableArray *)subelements;
{
long myType = [self typeAsLong];
@ -52,7 +52,7 @@
else subelements = nil;
return subelements;
}
*/
/* DATA ACCESSORS */
- (NSString *)string
@ -105,4 +105,9 @@
elementData.boolean = boolean;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"{ %@, %@ }", type, label];
}
@end

View File

@ -4,7 +4,7 @@
{
CLASS = TemplateWindowController;
LANGUAGE = ObjC;
OUTLETS = {fieldsMatrix = NSMatrix; };
OUTLETS = {containerView = NSView; };
SUPERCLASS = NSWindowController;
}
);

View File

@ -3,10 +3,26 @@
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>672 193 356 240 0 0 1600 1002 </string>
<string>276 97 356 240 0 0 1024 746 </string>
<key>IBEditorPositions</key>
<dict>
<key>22</key>
<string>114 377 480 236 0 0 1024 746 </string>
<key>45</key>
<string>163 366 480 162 0 0 1024 746 </string>
</dict>
<key>IBFramework Version</key>
<string>286.0</string>
<string>283.0</string>
<key>IBLockedObjects</key>
<array>
<integer>20</integer>
<integer>19</integer>
</array>
<key>IBOpenObjects</key>
<array>
<integer>5</integer>
</array>
<key>IBSystem Version</key>
<string>6D52</string>
<string>6G30</string>
</dict>
</plist>

View File

@ -5,7 +5,7 @@
@interface TemplateWindowController : NSWindowController <ResKnifePluginProtocol>
{
IBOutlet NSMatrix *fieldsMatrix;
IBOutlet NSView *containerView;
NSMutableArray *tmpl;
NSMutableArray *res;

View File

@ -27,7 +27,7 @@
tmpl = [[NSMutableArray alloc] init];
res = [[NSMutableArray alloc] init];
[self readTemplate:va_arg( resourceList, id )]; // reads (but doesn't retain) the TMPL resource
[self readTemplate:va_arg( resourceList, id )]; // reads (but doesn't retain) the template for this resource (TMPL resource with name equal to the passed resource's type)
while( currentResource = va_arg( resourceList, id ) )
NSLog( @"too many params passed to -initWithResources: %@", [currentResource description] );
va_end( resourceList );
@ -55,7 +55,7 @@
[[self window] setTitle:[resource name]];
// parse data using pre-scanned template and create the fields as needed
[self parseData];
[self readData];
[self createUI];
// insert the resources' data into the text fields
@ -88,29 +88,94 @@
currentByte += 4;
// add element to array
// NSLog( @"Adding object %@ of type %@ to array", label, type );
[tmpl addObject:[Element elementOfType:type withLabel:label]];
}
}
}
- (void)readData
{
// tmpl == array of Elements describing the template for this resource
// res == array of either Elements or Arrays containing the resource data
// this function creates the res instance variable, filling it with data from the resource if there's data available.
unsigned long position = 0; // position (byte offset) in resource I'm currently reading from
char *data = (char *) [[resource data] bytes]; // address of initial byte of resource in memory
unsigned long templateCounter = 0; // index into template array of the current template element
Element *currentTemplateElement; // current template element
NSMutableArray *targetStack = [NSMutableArray arrayWithObject:res]; // stack of arrays (target for addition of new elements)
NSMutableArray *loopStack = [NSMutableArray array]; // stack for 'LSTB' and 'LSTC' elements
NSMutableArray *loopCountStack = [NSMutableArray array]; // stack for counting how many times to loop
// when templateCounter >= [tmpl count], loop is only exited if targetStack has more than one target (this handles empty templates)
while( templateCounter < [tmpl count] || [targetStack count] > 1 )
{
currentTemplateElement = [tmpl objectAtIndex:templateCounter];
NSLog( @"template = %@", currentTemplateElement );
/* unsigned long type = [currentTemplateElement typeAsLong];
switch( type )
{
case 'BCNT':
case 'BZCT':
[resourceElement setNumberWithLong:*(unsigned char *)(data + position)];
lim = *(unsigned char *)(data + position) + (type == 'BZCT'? 1:0);
position += 1;
break;
case 'OCNT':
case 'ZCNT':
[resourceElement setNumberWithLong:*(unsigned short *)(data + position)];
lim = *(unsigned short *)(data + position) + (type == 'ZCNT'? 1:0);
position += 2;
break;
case 'LCNT':
case 'LZCT':
[resourceElement setNumberWithLong:*(unsigned long *)(data + position)];
lim = *(unsigned long *)(data + position) + (type == 'LZCT'? 1:0);
position += 4;
break;
case 'LSTB':
case 'LSTC':
[(NSMutableArray *)[targetStack lastObject] addObject:[NSMutableArray array]];
[loopStack addObject:currentTemplateElement]; // append the template loop start object to the array
break;
default:
// [(NSMutableArray *)[targetStack lastObject] addItem:[self createElementForTemplate:currentTemplateElement
}
*/
templateCounter++;
}
}
- (void)parseData
{
unsigned long position = 0;
char *data = (char *) [resource data];
char *data = (char *) [[resource data] bytes];
// used for nesting of elements, 'target' is current object to append to, targetStack is a FILO stack of mutable array pointers
// used for nesting of elements, 'target' is current object to append to, targetStack is a FILO stack of mutable array pointers, loopStack is a stack of element indicies to the start of loops, so I can go back to the head of a loop when iterating it
NSMutableArray *target = res;
NSMutableArray *targetArray = [NSMutableArray arrayWithObject:res];
NSMutableArray *targetStack = [NSMutableArray arrayWithObject:res];
NSMutableArray *loopStack = [NSMutableArray array];
// n = current item in TMPL to read, c = loop counter, when exiting loop, go back 'c' items in the template, lim is how many times to loop, obtained from a loop count
unsigned long n = 0, c = 0, lim = 0;
// 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;
NSEnumerator *enumerator = [tmpl objectEnumerator];
while( currentTemplateElement = [enumerator nextObject] )
// NSEnumerator *enumerator = [tmpl objectEnumerator];
// while( currentTemplateElement = [enumerator nextObject] )
while( position < [[resource size] unsignedLongValue] )
{
currentTemplateElement = [tmpl objectAtIndex:n];
n++, c++;
unsigned long type = [currentTemplateElement typeAsLong];
resourceElement = [[currentTemplateElement copy] autorelease];
NSLog( @"tmpl element = %@; position = %d", currentTemplateElement, position );
switch( type )
{
/* Alignment */
@ -163,38 +228,60 @@
// 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];
break;
/* Strings */
case 'CHAR':
[resourceElement setString:[[NSString alloc] initWithData:[NSData dataWithBytes:(void *)(data + position) length:1] encoding:NSMacOSRomanStringEncoding]];
position += 1;
break;
case 'TNAM':
[resourceElement setString:[[NSString alloc] initWithData:[NSData dataWithBytes:(void *)(data + position) length:4] encoding:NSMacOSRomanStringEncoding]];
position += 4;
break;
case 'PSTR':
[resourceElement setString:[[NSString alloc] initWithData:[NSData dataWithBytes:(void *)(data + position + 1) length:*(unsigned char *)(data + position)] encoding:NSMacOSRomanStringEncoding]];
position += *(unsigned char *)(data + position) + 1;
break;
/* List Counts */
case 'BCNT':
case 'BZCT':
// bug: how big are these various count fields?
[resourceElement setNumberWithLong:*(char *)(data + position)];
[resourceElement setNumberWithLong:*(unsigned char *)(data + position)];
lim = *(unsigned char *)(data + position) + (type == 'BZCT'? 1:0);
position += 1;
break;
case 'OCNT':
case 'ZCNT':
// bug: how big are these various count fields?
[resourceElement setNumberWithLong:*(short *)(data + position)];
[resourceElement setNumberWithLong:*(unsigned short *)(data + position)];
lim = *(unsigned short *)(data + position) + (type == 'ZCNT'? 1:0);
position += 2;
break;
case 'LCNT':
case 'LZCT':
// bug: how big are these various count fields?
[resourceElement setNumberWithLong:*(long *)(data + position)];
[resourceElement setNumberWithLong:*(unsigned long *)(data + position)];
lim = *(unsigned long *)(data + position) + (type == 'LZCT'? 1:0);
position += 4;
break;
/* List beginning and end */
case 'LSTB':
case 'LSTC':
target = [resourceElement subelements];
[targetArray addObject:target];
[target addObject:resourceElement]; // add list item to current target array
// target = [resourceElement subelements]; // change current array to list's sub-elements
[targetStack addObject:target]; // append sub-element array to target stack so it can be popped off afterwards
resourceElement = nil; // don't add item to it's own sub-elements later!
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
[targetStack removeLastObject]; // pop off current target from stack
target = [targetStack lastObject]; // set current target to whatever was second from top on the stack
resourceElement = nil; // list end items are not needed in a resource array
if( n < lim ) n -= c;
c = 0;
break;
/* Cxxx, Hxxx or P0xx */
@ -205,21 +292,26 @@
*/ char *lengthStr = (type & 0x00FFFFFF) & (3 << 24);
unsigned long length;
StringToNum(lengthStr, &length);
NSLog( @"error, Cxxx, Hxxx and P0xx unsupported, skipping %d bytes", length );
NSLog( @"error, '%@' is unsupported, skipping %d bytes", [resourceElement type], length );
resourceElement = nil; // relies on element being previously autoreleased to avoid a leak
position += length;
} break;
} // end switch
if( resourceElement ) [target addObject:resourceElement];
} // end while loop
} // end template element type switch
if( resourceElement )
{
NSLog( @"adding %@", resourceElement );
[target addObject:resourceElement];
}
} // end while position < size
NSLog( [target description] );
}
- (void)createUI
{
// iterate through res creating fields
// iterate through res (the resource element array) creating fields
[self enumerateElements:res];
NSLog( [fieldsMatrix description] );
[fieldsMatrix setNeedsDisplay];
}
- (void)enumerateElements:(NSMutableArray *)elements
@ -227,17 +319,21 @@
// iterate through the array of resource elements, creating fields
Element *currentResourceElement;
NSEnumerator *enumerator = [elements objectEnumerator];
NSLog( @"%d", [elements count] );
NSLog( @"elements in resource array = %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
// if element is a container (subelements != nil), iterate inside it first
/* if( [currentResourceElement subelements] )
{
NSFormCell *newField = [[NSFormCell alloc] initTextCell:[currentResourceElement label]];
[fieldsMatrix addRowWithCells:[NSArray arrayWithObject:[newField autorelease]]];
NSLog( @"%@ added to matrix", [newField description] );
// bug: need to indent view right
[self enumerateElements:[currentResourceElement subelements]];
// bug: need to remove indentation
}
else // element is normal
*/ {
/* NSFormCell *newField = [[NSFormCell alloc] initTextCell:[currentResourceElement label]];
[fieldsMatrix addRowWithCells:[NSArray arrayWithObject:[newField autorelease]]]; */
NSLog( [currentResourceElement description] );
}
}
}

View File

@ -54,7 +54,8 @@
- (void)parseForString:(NSString *)string sorted:(BOOL)sort
{
[self parseForString:string withinRange:NSMakeRange(-32767, 65536) sorted:sort];
// bug: for some reason +[NSNumber isBoundedByRange:] doesn't like a range with a minimum below -30,000 (such as INT16_MIN), so I'm using INT8_MIN and screw everyone using resource IDs below that :P
[self parseForString:string withinRange:NSMakeRange(INT8_MIN, INT16_MAX) sorted:sort];
}
- (void)parseForString:(NSString *)string withinRange:(NSRange)resIDRange sorted:(BOOL)sort
@ -63,6 +64,7 @@
NSString *trimmedString = [DataSource resNameFromStringValue:string];
NSEnumerator *enumerator = [[data allKeys] objectEnumerator];
[parsed removeAllObjects];
if( trimmedString == nil ) trimmedString = @"";
while( resID = [enumerator nextObject] )
{
NSString *value = [data objectForKey:resID];
@ -70,6 +72,11 @@
if( ((range.location != NSNotFound && range.length != 0) || [trimmedString isEqualToString:@""]) && [resID isBoundedByRange:resIDRange] )
[parsed addObject:[self stringValueForResID:resID]];
}
// crap hack to allow user to change the insertion point if what they typed doesn't yet match an existing resource
if( [parsed count] == 0 ) [parsed addObject:string];
// sort case insensitive if sorting is requested
if( sort ) [parsed sortUsingSelector:@selector(caseInsensitiveCompare:)];
}
@ -82,7 +89,7 @@
{
if( resID && [data objectForKey:resID] )
return [NSString stringWithFormat:@"%@ {%@}", [data objectForKey:resID], resID];
else if( [resID isEqualToNumber:[NSNumber numberWithInt:-1]] )
else if( [resID shortValue] == -1 )
return @"";
else if( resID )
return [NSString stringWithFormat:@"{%@}", resID];
@ -101,21 +108,17 @@
NS_DURING
NS_VALUERETURN( [[[NSNumber alloc] initWithInt:[[string substringWithRange:range] intValue]] autorelease], NSNumber* );
NS_HANDLER
NS_VALUERETURN( nil, NSNumber* );
NS_VALUERETURN( [NSNumber numberWithInt:-1], 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
}
if( range.location != NSNotFound && range.location > 0 )
return [string substringToIndex:range.location -1];
else if( range.location == 0 )
return nil;
else return string;
}

View File

@ -42,7 +42,8 @@
[[NSNotificationCenter defaultCenter] removeObserver:self];
[(id)resource autorelease];
[undoManager release];
[shipDataSource release]; // bug: release all data sources
[shipDataSource release];
[soundDataSource release];
[super dealloc];
}
@ -75,7 +76,7 @@
if( [[self window] isDocumentEdited] )
{
NSDictionary *errorValues = [self validateValues];
NSArray *fields = [errorValues allKeys];
NSArray *fields = [errorValues allKeys]; // bug: order of items in array is not guaranteed
NSArray *descriptions = [errorValues allValues];
switch( [errorValues count] )
{

View File

@ -2,6 +2,10 @@
#import <Carbon/Carbon.h>
#pragma options align=packed
// see http://developer.apple.com/techpubs/macosx/DeveloperTools/MachORuntime/2rt_powerpc_abi/PowerPC_Data_Alignment.html
// align=reset is at the bottom of the file.
typedef struct RLEPixelData
{
// 'rl#' resource
@ -577,7 +581,7 @@ typedef struct NebuRec
typedef struct BoomRec
{
short FrameAdvance; // 100 = normal speed, less is slower, higher faster
short SoundIndex; // 0-63 index, mapping to 300-363 resID
short SoundIndex; // 0-63 index, mapping to 300-363 resID, -1 == no sound
short GraphicIndex; // 0-63 index, mapping to 400-463 resID
} BoomRec;
@ -716,4 +720,6 @@ typedef struct IntfRec
short StatFontSize;
short SubtitleSize;
short StatusBkgnd;
} IntfRec;
} IntfRec;
#pragma options align=reset

View File

@ -1,12 +1,18 @@
#import <Cocoa/Cocoa.h>
#import "NovaWindowController.h"
enum
enum // boom defaults
{
kMinSpinID = 400,
kSpinIDRange = 64,
kMinSoundID = 300,
kSoundIDRange = 64
kMinBoomSpinID = 400,
kBoomSpinIDRange = 64,
kMinBoomSoundID = 300,
kBoomSoundIDRange = 64,
kMinBoomFrameAdvance = 1,
kBoomFrameAdvanceRange = 1000,
kDefaultBoomSpinID = kMinBoomSpinID,
kDefaultBoomSoundID = kMinBoomSoundID,
kDefaultBoomFrameAdvance = 100
};
@interface BoomWindowController : NovaWindowController

View File

@ -9,10 +9,19 @@
boomRec = (BoomRec *) calloc( 1, sizeof(BoomRec) );
[[newResource data] getBytes:boomRec];
// fill in default values if necessary
if( boomRec->GraphicIndex < 0 || boomRec->GraphicIndex > 63 )
boomRec->GraphicIndex = 0;
if( (boomRec->SoundIndex < 0 || boomRec->SoundIndex > 63) && (boomRec->SoundIndex != -1) )
boomRec->SoundIndex = 0;
if( boomRec->FrameAdvance < 1 || boomRec->FrameAdvance > 1000 )
boomRec->FrameAdvance = 100;
// use resource values to create NS objects
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)];
image = [[NSNumber alloc] initWithShort:boomRec->GraphicIndex + kMinBoomSpinID];
sound = [[NSNumber alloc] initWithShort:(silent? kMinBoomSoundID : boomRec->SoundIndex + kMinBoomSoundID)];
frameRate = [[NSNumber alloc] initWithShort:boomRec->FrameAdvance];
return self;
@ -33,6 +42,13 @@
[localCenter addObserver:self selector:@selector(controlTextDidChange:) name:NSComboBoxWillDismissNotification object:nil];
[localCenter addObserver:self selector:@selector(controlTextDidChange:) name:NSControlTextDidChangeNotification object:nil];
// mark window changed if initial values were invalid
if( ![[resource data] isEqualToData:[NSData dataWithBytes:boomRec length:sizeof(BoomRec)]] )
{
[resource touch];
[self setDocumentEdited:YES];
}
[self update];
[self showWindow:self];
}
@ -41,12 +57,10 @@
{
// 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];
@ -59,11 +73,11 @@
{
id sender = [notification object];
if( sender == graphicsField )
[spinDataSource parseForString:[sender stringValue] withinRange:NSMakeRange(kMinSpinID, kSpinIDRange) sorted:YES];
[spinDataSource parseForString:[sender stringValue] withinRange:NSMakeRange(kMinBoomSpinID, kBoomSpinIDRange) sorted:YES];
else if( sender == soundField )
[soundDataSource parseForString:[sender stringValue] withinRange:NSMakeRange(kMinSoundID, kSoundIDRange) sorted:YES];
[soundDataSource parseForString:[sender stringValue] withinRange:NSMakeRange(kMinBoomSoundID, kBoomSoundIDRange) sorted:YES];
if( [sender class] == NSClassFromString(@"NSComboBox") )
if( [sender class] == [NSComboBox class] )
[sender reloadData];
}
@ -121,9 +135,9 @@
{
NSMutableDictionary *errorValues = [NSMutableDictionary dictionary];
// get current values
boomRec->GraphicIndex = [image shortValue] -400;
boomRec->SoundIndex = [sound shortValue] -300;
// put current values into boomRec
boomRec->GraphicIndex = [image shortValue] - kMinBoomSpinID;
boomRec->SoundIndex = [sound shortValue] - kMinBoomSoundID;
boomRec->FrameAdvance = [frameRate shortValue];
if( silent ) boomRec->SoundIndex = -1;
@ -142,7 +156,7 @@
- (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)]];
[resource setData:[NSData dataWithBytes:boomRec length:sizeof(BoomRec)]];
}
@end

View File

@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<!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>161 150 356 240 0 0 1600 1002 </string>
<string>86 100 356 240 0 0 1024 746 </string>
<key>IBFramework Version</key>
<string>248.0</string>
<string>283.0</string>
<key>IBOpenObjects</key>
<array>
<integer>5</integer>
</array>
<key>IBSystem Version</key>
<string>5S66</string>
<string>6G30</string>
</dict>
</plist>

Binary file not shown.

View File

@ -48,7 +48,7 @@
IBOutlet NSComboBox *introPictField4;
IBOutlet NSForm *introDelayForm;
IBOutlet NSComboBox *introTextField;
IBOutlet NSImageView *introImageView;
IBOutlet NSButton *introImageView; // button so user can click to skip to next pic
IBOutlet NSTextView *introTextView;
IBOutlet NSForm *ncbForm;
@ -93,6 +93,7 @@
NSNumber *introDelay3;
NSNumber *introDelay4;
NSTimer *introPictTimer;
short currentPict;
// Nova Control Bits
NSString *onStart;
@ -101,6 +102,8 @@
- (void)update;
- (IBAction)editDate:(id)sender;
- (IBAction)stepDate:(id)sender;
- (IBAction)togglePrincipalChar:(id)sender;
- (void)rotateIntroPict:(NSTimer *)timer;
- (void)comboBoxWillPopUp:(NSNotification *)notification;
- (void)controlTextDidChange:(NSNotification *)notification;

View File

@ -10,13 +10,66 @@
// load data from resource
charRec = (CharRec *) calloc( 1, sizeof(CharRec) );
[[newResource data] getBytes:charRec];
// fill in default values if necessary
if( charRec->startYear == 0 || charRec->startMonth == 0 || charRec->startDay == 0 )
{
NSCalendarDate *today = [NSCalendarDate calendarDate];
charRec->startDay = [today dayOfMonth];
charRec->startMonth = [today monthOfYear];
charRec->startYear = [today yearOfCommonEra];
}
// set ship to -1 if unused
if( charRec->startShipType == 0 ) charRec->startShipType = -1;
// set unused starting locations to -1
if( charRec->startSystem[0] == 0 ) charRec->startSystem[0] = -1;
if( charRec->startSystem[1] == 0 ) charRec->startSystem[1] = -1;
if( charRec->startSystem[2] == 0 ) charRec->startSystem[2] = -1;
if( charRec->startSystem[3] == 0 ) charRec->startSystem[3] = -1;
// set unused governments to -1
if( charRec->startGovt[0] == 0 ) charRec->startGovt[0] = -1;
if( charRec->startGovt[1] == 0 ) charRec->startGovt[1] = -1;
if( charRec->startGovt[2] == 0 ) charRec->startGovt[2] = -1;
if( charRec->startGovt[3] == 0 ) charRec->startGovt[3] = -1;
// set unused government's status' to -1
if( charRec->startGovt[0] == -1 ) charRec->startStatus[0] = -1;
if( charRec->startGovt[1] == -1 ) charRec->startStatus[1] = -1;
if( charRec->startGovt[2] == -1 ) charRec->startStatus[2] = -1;
if( charRec->startGovt[3] == -1 ) charRec->startStatus[3] = -1;
// set unused intro text to -1
if( charRec->introTextID == 0 ) charRec->introTextID = -1;
// set unused intro picts to -1
if( charRec->introPictID[0] == 0 ) charRec->introPictID[0] = -1;
if( charRec->introPictID[1] == 0 ) charRec->introPictID[1] = -1;
if( charRec->introPictID[2] == 0 ) charRec->introPictID[2] = -1;
if( charRec->introPictID[3] == 0 ) charRec->introPictID[3] = -1;
// set unused/invalid intro pict delays to -1
if( charRec->introPictDelay[0] < 1 || charRec->introPictDelay[0] > 300 )
charRec->introPictDelay[0] = -1;
if( charRec->introPictDelay[1] < 1 || charRec->introPictDelay[1] > 300 )
charRec->introPictDelay[1] = -1;
if( charRec->introPictDelay[2] < 1 || charRec->introPictDelay[2] > 300 )
charRec->introPictDelay[2] = -1;
if( charRec->introPictDelay[3] < 1 || charRec->introPictDelay[3] > 300 )
charRec->introPictDelay[3] = -1;
// use resource values to create NS objects
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];
suffix = [[NSString alloc] initWithCString:charRec->Suffix length:16];
NSString *tempPrefix = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->Prefix length:16] encoding:NSMacOSRomanStringEncoding] autorelease];
prefix = [[NSString alloc] initWithCString:[tempPrefix cString] length:[tempPrefix cStringLength]];
NSString *tempSuffix = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->Suffix length:16] encoding:NSMacOSRomanStringEncoding] autorelease];
suffix = [[NSString alloc] initWithCString:[tempSuffix cString] length:[tempSuffix cStringLength]];
start1 = [[NSNumber alloc] initWithShort:charRec->startSystem[0]];
start2 = [[NSNumber alloc] initWithShort:charRec->startSystem[1]];
start3 = [[NSNumber alloc] initWithShort:charRec->startSystem[2]];
@ -38,8 +91,12 @@
introDelay2 = [[NSNumber alloc] initWithShort:charRec->introPictDelay[1]];
introDelay3 = [[NSNumber alloc] initWithShort:charRec->introPictDelay[2]];
introDelay4 = [[NSNumber alloc] initWithShort:charRec->introPictDelay[3]];
onStart = [[NSString alloc] initWithCString:charRec->OnStart length:256];
NSString *tempStart = [[[NSString alloc] initWithData:[NSData dataWithBytes:charRec->OnStart length:256] encoding:NSMacOSRomanStringEncoding] autorelease];
onStart = [[NSString alloc] initWithCString:[tempStart cString] length:[tempStart cStringLength]];
// rotating image
currentPict = 0;
return self;
}
@ -80,6 +137,7 @@
[introPictField3 setDataSource:pictureDataSource];
[introPictField4 setDelegate:pictureDataSource];
[introPictField4 setDataSource:pictureDataSource];
[introTextField setDelegate:descriptionDataSource];
[introTextField setDataSource:descriptionDataSource];
// set notifications for ending editing on a combo box
@ -87,6 +145,16 @@
[localCenter addObserver:self selector:@selector(controlTextDidChange:) name:NSComboBoxWillDismissNotification object:nil];
[localCenter addObserver:self selector:@selector(controlTextDidChange:) name:NSControlTextDidChangeNotification object:nil];
// mark window changed if initial values were invalid
if( ![[resource data] isEqualToData:[NSData dataWithBytes:charRec length:sizeof(CharRec)]] )
{
[resource touch];
[self setDocumentEdited:YES];
}
// set initial picture
[self rotateIntroPict:nil];
// finally, show the window
[self update];
[self showWindow:self];
@ -113,47 +181,38 @@
[suffixField setStringValue:suffix];
// starting locations
if( [start1 isEqualToNumber:[NSNumber numberWithInt:-1]] ) [startField1 setObjectValue:nil];
else [startField1 setObjectValue:[planetDataSource stringValueForResID:start1]];
if( [start2 isEqualToNumber:[NSNumber numberWithInt:-1]] ) [startField2 setObjectValue:nil];
else [startField2 setObjectValue:[planetDataSource stringValueForResID:start2]];
if( [start3 isEqualToNumber:[NSNumber numberWithInt:-1]] ) [startField3 setObjectValue:nil];
else [startField3 setObjectValue:[planetDataSource stringValueForResID:start3]];
if( [start4 isEqualToNumber:[NSNumber numberWithInt:-1]] ) [startField4 setObjectValue:nil];
else [startField4 setObjectValue:[planetDataSource stringValueForResID:start4]];
[startField1 setObjectValue:[planetDataSource stringValueForResID:start1]];
[startField2 setObjectValue:[planetDataSource stringValueForResID:start2]];
[startField3 setObjectValue:[planetDataSource stringValueForResID:start3]];
[startField4 setObjectValue:[planetDataSource stringValueForResID:start4]];
// governments
[statusField1 setObjectValue:status1];
[statusField2 setObjectValue:status2];
[statusField3 setObjectValue:status3];
[statusField4 setObjectValue:status4];
if( [government1 isEqualToNumber:[NSNumber numberWithInt:-1]] ) [governmentField1 setObjectValue:nil];
else [governmentField1 setObjectValue:[governmentDataSource stringValueForResID:government1]];
if( [government2 isEqualToNumber:[NSNumber numberWithInt:-1]] ) [governmentField2 setObjectValue:nil];
else [governmentField2 setObjectValue:[governmentDataSource stringValueForResID:government2]];
if( [government3 isEqualToNumber:[NSNumber numberWithInt:-1]] ) [governmentField3 setObjectValue:nil];
else [governmentField3 setObjectValue:[governmentDataSource stringValueForResID:government3]];
if( [government4 isEqualToNumber:[NSNumber numberWithInt:-1]] ) [governmentField4 setObjectValue:nil];
else [governmentField4 setObjectValue:[governmentDataSource stringValueForResID:government4]];
[governmentField1 setObjectValue:[governmentDataSource stringValueForResID:government1]];
[governmentField2 setObjectValue:[governmentDataSource stringValueForResID:government2]];
[governmentField3 setObjectValue:[governmentDataSource stringValueForResID:government3]];
[governmentField4 setObjectValue:[governmentDataSource stringValueForResID:government4]];
// intro text & pics
if( [introPict1 isEqualToNumber:[NSNumber numberWithInt:-1]] ) [introPictField1 setObjectValue:nil];
else [introPictField1 setObjectValue:[governmentDataSource stringValueForResID:government1]];
if( [introPict2 isEqualToNumber:[NSNumber numberWithInt:-1]] ) [introPictField2 setObjectValue:nil];
else [introPictField2 setObjectValue:[governmentDataSource stringValueForResID:government2]];
if( [introPict3 isEqualToNumber:[NSNumber numberWithInt:-1]] ) [introPictField3 setObjectValue:nil];
else [introPictField3 setObjectValue:[governmentDataSource stringValueForResID:government3]];
if( [introPict4 isEqualToNumber:[NSNumber numberWithInt:-1]] ) [introPictField4 setObjectValue:nil];
else [introPictField4 setObjectValue:[governmentDataSource stringValueForResID:government4]];
if( [introText isEqualToNumber:[NSNumber numberWithInt:-1]] ) [introTextField setObjectValue:nil];
else [introTextField setObjectValue:[descriptionDataSource stringValueForResID:introText]];
[introDelayField1 setObjectValue:introDelay1];
[introDelayField2 setObjectValue:introDelay2];
[introDelayField3 setObjectValue:introDelay3];
[introDelayField4 setObjectValue:introDelay4];
[introPictField1 setObjectValue:[pictureDataSource stringValueForResID:introPict1]];
[introPictField2 setObjectValue:[pictureDataSource stringValueForResID:introPict2]];
[introPictField3 setObjectValue:[pictureDataSource stringValueForResID:introPict3]];
[introPictField4 setObjectValue:[pictureDataSource stringValueForResID:introPict4]];
[introTextField setObjectValue:[descriptionDataSource stringValueForResID:introText]];
NSData *stringData = [(id <ResKnifeResourceProtocol>)[NSClassFromString(@"Resource") getResourceOfType:[plugBundle localizedStringForKey:@"desc" value:@"" table:@"Resource Types"] andID:introText inDocument:nil] data];
if( stringData != nil )
{
const char *stringData = [[(id <ResKnifeResourceProtocol>)[NSClassFromString(@"Resource") getResourceOfType:[plugBundle localizedStringForKey:@"desc" value:@"" table:@"Resource Types"] andID:introText inDocument:nil] data] bytes];
if( stringData != NULL )
[introTextView setString:[NSString stringWithCString:stringData]];
[introTextView setString:[[[NSString alloc] initWithData:stringData encoding:NSMacOSRomanStringEncoding] autorelease]];
// [introTextView scrollToTop]; // bug: made up method - needs implementing
}
// ncbs
[onStartField setStringValue:onStart];
}
@ -174,6 +233,61 @@
[self update];
}
- (IBAction)togglePrincipalChar:(id)sender
{
principalChar = [principalCharButton state];
[resource touch];
[self setDocumentEdited:YES];
}
- (IBAction)rotateIntroPictEarly:(id)sender
{
[introPictTimer fire];
}
- (void)rotateIntroPict:(NSTimer *)timer
{
// identify next frame
currentPict++;
if( currentPict == 2 && [introPict2 intValue] == -1 ) currentPict = 1;
else if( currentPict == 3 && [introPict3 intValue] == -1 ) currentPict = 1;
else if( currentPict == 4 && [introPict4 intValue] == -1 ) currentPict = 1;
else if( currentPict > 4 ) currentPict = 1;
// install new timer
switch( currentPict )
{
case 1:
// install new timer
introPictTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)[introDelay1 doubleValue] target:self selector:@selector(rotateIntroPict:) userInfo:nil repeats:NO];
// set next picture
[introImageView setImage:[[[NSImage alloc] initWithData:[(id <ResKnifeResourceProtocol>)[NSClassFromString(@"Resource") getResourceOfType:[plugBundle localizedStringForKey:@"PICT" value:@"" table:@"Resource Types"] andID:introPict1 inDocument:nil] data]] autorelease]];
break;
case 2:
// install new timer
introPictTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)[introDelay2 doubleValue] target:self selector:@selector(rotateIntroPict:) userInfo:nil repeats:NO];
// set next picture
[introImageView setImage:[[[NSImage alloc] initWithData:[(id <ResKnifeResourceProtocol>)[NSClassFromString(@"Resource") getResourceOfType:[plugBundle localizedStringForKey:@"PICT" value:@"" table:@"Resource Types"] andID:introPict2 inDocument:nil] data]] autorelease]];
break;
case 3:
// install new timer
introPictTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)[introDelay3 doubleValue] target:self selector:@selector(rotateIntroPict:) userInfo:nil repeats:NO];
// set next picture
[introImageView setImage:[[[NSImage alloc] initWithData:[(id <ResKnifeResourceProtocol>)[NSClassFromString(@"Resource") getResourceOfType:[plugBundle localizedStringForKey:@"PICT" value:@"" table:@"Resource Types"] andID:introPict3 inDocument:nil] data]] autorelease]];
break;
case 4:
// install new timer
introPictTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)[introDelay4 doubleValue] target:self selector:@selector(rotateIntroPict:) userInfo:nil repeats:NO];
// set next picture
[introImageView setImage:[[[NSImage alloc] initWithData:[(id <ResKnifeResourceProtocol>)[NSClassFromString(@"Resource") getResourceOfType:[plugBundle localizedStringForKey:@"PICT" value:@"" table:@"Resource Types"] andID:introPict4 inDocument:nil] data]] autorelease]];
break;
}
}
- (void)comboBoxWillPopUp:(NSNotification *)notification
{
id sender = [notification object];
@ -188,79 +302,160 @@
else if( sender == introTextField )
[descriptionDataSource parseForString:[sender stringValue] sorted:YES];
if( [sender class] == NSClassFromString(@"NSComboBox") )
if( [sender class] == [NSComboBox class] )
[sender reloadData];
}
- (void)controlTextDidChange:(NSNotification *)notification
{
// get the control or form cell being changed
id sender = [notification object];
if( [sender class] == [NSForm class] )
sender = [sender cellAtIndex:[sender indexOfSelectedItem]];
/* ship combo box */
if( sender == shipField )
/* ship, cash, kills */
if( sender == shipField && [sender stringValue] )
{
id old = ship;
ship = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![ship isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == cashField )
{
id old = cash;
cash = [[NSNumber alloc] initWithInt:[sender intValue]];
if( ![cash isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == killsField )
{
id old = kills;
kills = [[NSNumber alloc] initWithInt:[sender intValue]];
if( ![kills isEqualToNumber:old] ) [resource touch];
[old release];
}
/* start date */
else if( sender == dayField || sender == dayStepper )
{
id old = date;
date = [[NSCalendarDate alloc] initWithYear:[old yearOfCommonEra] month:[old monthOfYear] day:[sender intValue] hour:0 minute:0 second:0 timeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];;
if( ![date isEqualToDate:old] ) [resource touch];
[old release];
}
else if( sender == monthField || sender == monthStepper )
{
id old = date;
date = [[NSCalendarDate alloc] initWithYear:[old yearOfCommonEra] month:[sender intValue] day:[old dayOfMonth] hour:0 minute:0 second:0 timeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];;
if( ![date isEqualToDate:old] ) [resource touch];
[old release];
}
else if( sender == yearField || sender == yearStepper )
{
id old = date;
date = [[NSCalendarDate alloc] initWithYear:[sender intValue] month:[old monthOfYear] day:[old dayOfMonth] hour:0 minute:0 second:0 timeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];;
if( ![date isEqualToDate:old] ) [resource touch];
[old release];
}
else if( sender == prefixField && [sender stringValue] )
{
id old = prefix;
prefix = [[sender stringValue] retain];
if( ![prefix isEqualToString:old] ) [resource touch];
[old release];
}
else if( sender == suffixField && [sender stringValue] )
{
id old = suffix;
suffix = [[sender stringValue] retain];
if( ![suffix isEqualToString:old] ) [resource touch];
[old release];
}
/* planet combo boxes */
else if( sender == startField1 )
else if( sender == startField1 && [sender stringValue] )
{
id old = start1;
start1 = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![start1 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == startField2 )
else if( sender == startField2 && [sender stringValue] )
{
id old = start2;
start2 = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![start2 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == startField3 )
else if( sender == startField3 && [sender stringValue] )
{
id old = start3;
start3 = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![start3 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == startField4 )
else if( sender == startField4 && [sender stringValue] )
{
id old = start4;
start4 = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![start4 isEqualToNumber:old] ) [resource touch];
[old release];
}
/* starting government status */
else if( sender == statusField1 )
{
id old = status1;
status1 = [[NSNumber alloc] initWithInt:[sender intValue]];
if( ![status1 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == statusField2 )
{
id old = status2;
status2 = [[NSNumber alloc] initWithInt:[sender intValue]];
if( ![status2 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == statusField3 )
{
id old = status3;
status3 = [[NSNumber alloc] initWithInt:[sender intValue]];
if( ![status3 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == statusField4 )
{
id old = status4;
status4 = [[NSNumber alloc] initWithInt:[sender intValue]];
if( ![status4 isEqualToNumber:old] ) [resource touch];
[old release];
}
/* government combo boxes */
else if( sender == governmentField1 )
else if( sender == governmentField1 && [sender stringValue] )
{
id old = government1;
government1 = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![government1 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == governmentField2 )
else if( sender == governmentField2 && [sender stringValue] )
{
id old = government2;
government2 = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![government2 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == governmentField3 )
else if( sender == governmentField3 && [sender stringValue] )
{
id old = government3;
government3 = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![government3 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == governmentField4 )
else if( sender == governmentField4 && [sender stringValue] )
{
id old = government4;
government4 = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
@ -268,44 +463,85 @@
[old release];
}
/* planet combo boxes */
/* intro text combo box */
else if( sender == introTextField && [sender stringValue] )
{
id old = introText;
introText = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![introText isEqualToNumber:old] )
{
[resource touch];
[self update]; // to draw text in text box
}
[old release];
}
else if( sender == introPictField1 )
/* intro picture combo boxes */
else if( sender == introPictField1 && [sender stringValue] )
{
id old = introPict1;
introPict1 = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![introPict1 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == introPictField2 )
else if( sender == introPictField2 && [sender stringValue] )
{
id old = introPict2;
introPict2 = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![introPict2 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == introPictField3 )
else if( sender == introPictField3 && [sender stringValue] )
{
id old = introPict3;
introPict3 = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![introPict3 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == introPictField4 )
else if( sender == introPictField4 && [sender stringValue] )
{
id old = introPict4;
introPict4 = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![introPict4 isEqualToNumber:old] ) [resource touch];
[old release];
}
/* intro text combo box */
else if( sender == introTextField )
/* intro picture delays */
else if( sender == introDelayField1 )
{
id old = introText;
introText = [[DataSource resIDFromStringValue:[sender stringValue]] retain];
if( ![introText isEqualToNumber:old] ) [resource touch];
id old = introDelay1;
introDelay1 = [[NSNumber alloc] initWithInt:[sender intValue]];
if( ![introDelay1 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == introDelayField2 )
{
id old = introDelay2;
introDelay2 = [[NSNumber alloc] initWithInt:[sender intValue]];
if( ![introDelay2 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == introDelayField3 )
{
id old = introDelay3;
introDelay3 = [[NSNumber alloc] initWithInt:[sender intValue]];
if( ![introDelay3 isEqualToNumber:old] ) [resource touch];
[old release];
}
else if( sender == introDelayField4 )
{
id old = introDelay4;
introDelay4 = [[NSNumber alloc] initWithInt:[sender intValue]];
if( ![introDelay4 isEqualToNumber:old] ) [resource touch];
[old release];
}
/* on start field */
else if( sender == onStartField && [sender stringValue] )
{
id old = onStart;
onStart = [[sender stringValue] retain];
if( ![onStart isEqualToString:old] ) [resource touch];
[old release];
}
@ -314,4 +550,69 @@
[self setDocumentEdited:[resource isDirty]];
}
- (NSDictionary *)validateValues
{
NSMutableDictionary *errorValues = [NSMutableDictionary dictionary];
// put current values into boomRec
charRec->Flags = 0x0000;
charRec->Flags |= principalChar? 0x0001:0;
charRec->startShipType = [ship shortValue];
charRec->startCash = [cash longValue];
charRec->startKills = [kills shortValue];
charRec->startDay = [date dayOfMonth];
charRec->startMonth = [date monthOfYear];
charRec->startYear = [date yearOfCommonEra];
BlockZero( charRec->Prefix, 16 );
BlockMoveData( [prefix cString], charRec->Prefix, [prefix cStringLength] <= 15? [prefix cStringLength]+1:16 );
BlockZero( charRec->Suffix, 16 );
BlockMoveData( [suffix cString], charRec->Suffix, [suffix cStringLength] <= 15? [suffix cStringLength]+1:16 );
charRec->startSystem[0] = [start1 shortValue];
charRec->startSystem[1] = [start2 shortValue];
charRec->startSystem[2] = [start3 shortValue];
charRec->startSystem[3] = [start4 shortValue];
charRec->startGovt[0] = [government1 shortValue];
charRec->startGovt[1] = [government2 shortValue];
charRec->startGovt[2] = [government3 shortValue];
charRec->startGovt[3] = [government4 shortValue];
charRec->startStatus[0] = [status1 shortValue];
charRec->startStatus[1] = [status2 shortValue];
charRec->startStatus[2] = [status3 shortValue];
charRec->startStatus[3] = [status4 shortValue];
charRec->introTextID = [introText shortValue];
charRec->introPictID[0] = [introPict1 shortValue];
charRec->introPictID[1] = [introPict2 shortValue];
charRec->introPictID[2] = [introPict3 shortValue];
charRec->introPictID[3] = [introPict4 shortValue];
charRec->introPictDelay[0] = [introDelay1 shortValue];
charRec->introPictDelay[1] = [introDelay2 shortValue];
charRec->introPictDelay[2] = [introDelay3 shortValue];
charRec->introPictDelay[3] = [introDelay4 shortValue];
BlockZero( charRec->OnStart, 256 );
BlockMoveData( [onStart cString], charRec->OnStart, [onStart cStringLength] <= 255? [onStart cStringLength]+1:256 );
BlockZero( charRec->UnusedA, 8*sizeof(short) );
// verify values are valid
if(charRec->startDay < 1 || charRec->startDay > 31 )
[errorValues setObject:@"must be between 1 and 31." forKey:@"Start Day"];
if( charRec->startMonth < 1 || charRec->startMonth > 12 )
[errorValues setObject:@"must be between 1 and 12." forKey:@"Start Month"];
if( charRec->startYear < 1 )
[errorValues setObject:@"must be above zero." forKey:@"Start Year"];
if(((charRec->introPictDelay[0] < 1 || charRec->introPictDelay[0] > 300) && (charRec->introPictDelay[0] != -1))
|| ((charRec->introPictDelay[1] < 1 || charRec->introPictDelay[1] > 300) && (charRec->introPictDelay[1] != -1))
|| ((charRec->introPictDelay[2] < 1 || charRec->introPictDelay[2] > 300) && (charRec->introPictDelay[2] != -1))
|| ((charRec->introPictDelay[3] < 1 || charRec->introPictDelay[3] > 300) && (charRec->introPictDelay[3] != -1)))
[errorValues setObject:@"valid delays are 1 to 300 seconds, or -1 for unused values." forKey:@"Intro Picture Delays"];
// all values fell within acceptable range
return errorValues;
}
- (void)saveResource
{
// save new data into resource structure (should have already been validated, and charRec filled out correctly)
[resource setData:[NSData dataWithBytes:charRec length:sizeof(CharRec)]];
}
@end

View File

@ -1,7 +1,12 @@
{
IBClasses = (
{
ACTIONS = {editDate = id; stepDate = id; };
ACTIONS = {
editDate = id;
rotateIntroPictEarly = id;
stepDate = id;
togglePrincipalChar = id;
};
CLASS = CharWindowController;
LANGUAGE = ObjC;
OUTLETS = {
@ -13,7 +18,7 @@
governmentField3 = NSComboBox;
governmentField4 = NSComboBox;
introDelayForm = NSForm;
introImageView = NSImageView;
introImageView = NSButton;
introPictField1 = NSComboBox;
introPictField2 = NSComboBox;
introPictField3 = NSComboBox;
@ -23,7 +28,7 @@
monthField = NSTextField;
monthStepper = NSStepper;
ncbForm = NSForm;
principalChar = NSButton;
principalCharButton = NSButton;
shipField = NSComboBox;
startField1 = NSComboBox;
startField2 = NSComboBox;

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<!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>47 148 356 240 0 0 1600 1002 </string>
<string>308 330 356 240 0 0 1024 746 </string>
<key>IBFramework Version</key>
<string>248.0</string>
<string>283.0</string>
<key>IBGroupedObjects</key>
<dict>
<key>2</key>
@ -20,11 +20,7 @@
</dict>
<key>IBLastGroupID</key>
<string>3</string>
<key>IBOpenObjects</key>
<array>
<integer>137</integer>
</array>
<key>IBSystem Version</key>
<string>5S66</string>
<string>6G30</string>
</dict>
</plist>

Binary file not shown.

View File

@ -736,12 +736,6 @@
path = "ResKnife-rsrcfork.rsrc";
refType = 4;
};
F54627050291767E01A8010C = {
fileRef = F54627040291767E01A8010C;
isa = PBXBuildFile;
settings = {
};
};
F546270B02917D1501A8010C = {
buildActionMask = 2147483647;
files = (
@ -2656,7 +2650,7 @@
buildActionMask = 2147483647;
files = (
F5B588CF0156D6D901000001,
F54627050291767E01A8010C,
F7634BC703B90A220107CC6F,
);
isa = PBXRezBuildPhase;
runOnlyForDeploymentPostprocessing = 0;
@ -4087,6 +4081,7 @@
F5EDC61D025BFB8E01A8010C,
F5EDC620025BFBB501A8010C,
F543AFF1027C716E01A8010C,
F7C028FE03BBB39D017A2919,
);
isa = PBXResourcesBuildPhase;
runOnlyForDeploymentPostprocessing = 0;
@ -4126,6 +4121,7 @@
};
F5DF1C0F0254C78801A80001 = {
children = (
F7C028FD03BBB39D017A2919,
F58F6B82025BC73001A8010C,
F58F6B83025BC73001A8010C,
F58F6B7E025BC3A501A8010C,
@ -4417,6 +4413,33 @@
//F52
//F53
//F54
//F70
//F71
//F72
//F73
//F74
F7634BC703B90A220107CC6F = {
fileRef = F5B588A50156D6D901000001;
isa = PBXBuildFile;
settings = {
};
};
F7C028FD03BBB39D017A2919 = {
isa = PBXFileReference;
path = novabible.html;
refType = 4;
};
F7C028FE03BBB39D017A2919 = {
fileRef = F7C028FD03BBB39D017A2919;
isa = PBXBuildFile;
settings = {
};
};
//F70
//F71
//F72
//F73
//F74
//FD0
//FD1
//FD2