diff --git a/Carbon/Classes/Application.cpp b/Carbon/Classes/Application.cpp index 9444f04..78587da 100644 --- a/Carbon/Classes/Application.cpp +++ b/Carbon/Classes/Application.cpp @@ -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; diff --git a/Carbon/Classes/EditorWindow.cpp b/Carbon/Classes/EditorWindow.cpp index 4ef91b3..eab3e0f 100644 --- a/Carbon/Classes/EditorWindow.cpp +++ b/Carbon/Classes/EditorWindow.cpp @@ -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; diff --git a/Carbon/Classes/FileWindow.cpp b/Carbon/Classes/FileWindow.cpp index a998b48..4db5a65 100644 --- a/Carbon/Classes/FileWindow.cpp +++ b/Carbon/Classes/FileWindow.cpp @@ -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 diff --git a/Carbon/Classes/Files.cpp b/Carbon/Classes/Files.cpp index ba2037f..8dfb1c3 100644 --- a/Carbon/Classes/Files.cpp +++ b/Carbon/Classes/Files.cpp @@ -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: diff --git a/Carbon/Classes/HostCallbacks.cpp b/Carbon/Classes/HostCallbacks.cpp index d094750..73ad867 100644 --- a/Carbon/Classes/HostCallbacks.cpp +++ b/Carbon/Classes/HostCallbacks.cpp @@ -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; diff --git a/Carbon/Classes/InspectorWindow.cpp b/Carbon/Classes/InspectorWindow.cpp index e6308ef..3815800 100644 --- a/Carbon/Classes/InspectorWindow.cpp +++ b/Carbon/Classes/InspectorWindow.cpp @@ -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 ***/ diff --git a/Cocoa/Categories/NSString-FSSpec.m b/Cocoa/Categories/NSString-FSSpec.m index d3193e8..5bcb098 100644 --- a/Cocoa/Categories/NSString-FSSpec.m +++ b/Cocoa/Categories/NSString-FSSpec.m @@ -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; } diff --git a/Cocoa/Classes/Resource.h b/Cocoa/Classes/Resource.h index 3bb149b..bf24153 100644 --- a/Cocoa/Classes/Resource.h +++ b/Cocoa/Classes/Resource.h @@ -1,7 +1,7 @@ #import #import "ResKnifeResourceProtocol.h" -@interface Resource : NSObject +@interface Resource : NSObject { @private // flags diff --git a/Cocoa/Classes/Resource.m b/Cocoa/Classes/Resource.m index 7257084..1acd289 100644 --- a/Cocoa/Classes/Resource.m +++ b/Cocoa/Classes/Resource.m @@ -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 diff --git a/Cocoa/Classes/ResourceDocument.m b/Cocoa/Classes/ResourceDocument.m index d000a65..c276569 100644 --- a/Cocoa/Classes/ResourceDocument.m +++ b/Cocoa/Classes/ResourceDocument.m @@ -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. diff --git a/Cocoa/Classes/ResourceNameCell.m b/Cocoa/Classes/ResourceNameCell.m index 679a6dc..2d3528e 100644 --- a/Cocoa/Classes/ResourceNameCell.m +++ b/Cocoa/Classes/ResourceNameCell.m @@ -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 diff --git a/Cocoa/Plug-Ins/Hex Editor/English.lproj/FindSheet.nib/info.nib b/Cocoa/Plug-Ins/Hex Editor/English.lproj/FindSheet.nib/info.nib index cb6812f..3f684dd 100644 --- a/Cocoa/Plug-Ins/Hex Editor/English.lproj/FindSheet.nib/info.nib +++ b/Cocoa/Plug-Ins/Hex Editor/English.lproj/FindSheet.nib/info.nib @@ -3,9 +3,9 @@ IBDocumentLocation - 681 234 356 240 0 0 1600 1002 + 366 155 356 240 0 0 1024 746 IBFramework Version - 286.0 + 283.0 IBGroupedObjects 0 @@ -26,6 +26,6 @@ 7 IBSystem Version - 6F21 + 6G30 diff --git a/Cocoa/Plug-Ins/Hex Editor/English.lproj/FindSheet.nib/objects.nib b/Cocoa/Plug-Ins/Hex Editor/English.lproj/FindSheet.nib/objects.nib index 6107e1f..007f204 100644 Binary files a/Cocoa/Plug-Ins/Hex Editor/English.lproj/FindSheet.nib/objects.nib and b/Cocoa/Plug-Ins/Hex Editor/English.lproj/FindSheet.nib/objects.nib differ diff --git a/Cocoa/Plug-Ins/Hex Editor/FindSheetController.m b/Cocoa/Plug-Ins/Hex Editor/FindSheetController.m index 11f1f07..d448e7a 100644 --- a/Cocoa/Plug-Ins/Hex Editor/FindSheetController.m +++ b/Cocoa/Plug-Ins/Hex Editor/FindSheetController.m @@ -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]; } diff --git a/Cocoa/Plug-Ins/Hex Editor/HexTextView.h b/Cocoa/Plug-Ins/Hex Editor/HexTextView.h index 59bd750..4542d95 100644 --- a/Cocoa/Plug-Ins/Hex Editor/HexTextView.h +++ b/Cocoa/Plug-Ins/Hex Editor/HexTextView.h @@ -5,6 +5,7 @@ @interface HexTextView : NSTextView { } +- (IBAction)clear:(id)sender; - (IBAction)pasteAsASCII:(id)sender; - (IBAction)pasteAsHex:(id)sender; - (IBAction)pasteAsUnicode:(id)sender; diff --git a/Cocoa/Plug-Ins/Hex Editor/HexTextView.m b/Cocoa/Plug-Ins/Hex Editor/HexTextView.m index 6069f92..6f9e74e 100644 --- a/Cocoa/Plug-Ins/Hex Editor/HexTextView.m +++ b/Cocoa/Plug-Ins/Hex Editor/HexTextView.m @@ -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]; diff --git a/Cocoa/Plug-Ins/Hex Editor/HexWindowController.h b/Cocoa/Plug-Ins/Hex Editor/HexWindowController.h index 36acdea..7097100 100644 --- a/Cocoa/Plug-Ins/Hex Editor/HexWindowController.h +++ b/Cocoa/Plug-Ins/Hex Editor/HexWindowController.h @@ -21,6 +21,8 @@ NSUndoManager *undoManager; id resource; + id 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 diff --git a/Cocoa/Plug-Ins/Hex Editor/HexWindowController.m b/Cocoa/Plug-Ins/Hex Editor/HexWindowController.m index 14dff00..46636b0 100644 --- a/Cocoa/Plug-Ins/Hex Editor/HexWindowController.m +++ b/Cocoa/Plug-Ins/Hex Editor/HexWindowController.m @@ -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; diff --git a/Cocoa/Plug-Ins/Notifications.m b/Cocoa/Plug-Ins/Notifications.m index be448a9..97b76e9 100644 --- a/Cocoa/Plug-Ins/Notifications.m +++ b/Cocoa/Plug-Ins/Notifications.m @@ -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"; \ No newline at end of file +NSString *ResourceDidChangeNotification = @"ResourceDidChangeNotification"; +NSString *ResourceWasSavedNotification = @"ResourceWasSavedNotification"; diff --git a/Cocoa/Plug-Ins/ResKnifeResourceProtocol.h b/Cocoa/Plug-Ins/ResKnifeResourceProtocol.h index 0ac7fe6..0c1dd72 100644 --- a/Cocoa/Plug-Ins/ResKnifeResourceProtocol.h +++ b/Cocoa/Plug-Ins/ResKnifeResourceProtocol.h @@ -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; \ No newline at end of file +extern NSString *ResourceDidChangeNotification; +extern NSString *ResourceWasSavedNotification; \ No newline at end of file diff --git a/Cocoa/Plug-Ins/Template Editor/Element.h b/Cocoa/Plug-Ins/Template Editor/Element.h index 5c1284c..5d08b07 100644 --- a/Cocoa/Plug-Ins/Template Editor/Element.h +++ b/Cocoa/Plug-Ins/Template Editor/Element.h @@ -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; diff --git a/Cocoa/Plug-Ins/Template Editor/Element.m b/Cocoa/Plug-Ins/Template Editor/Element.m index 3c1ccb4..0f3194b 100644 --- a/Cocoa/Plug-Ins/Template Editor/Element.m +++ b/Cocoa/Plug-Ins/Template Editor/Element.m @@ -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 diff --git a/Cocoa/Plug-Ins/Template Editor/English.lproj/TemplateWindow.nib/classes.nib b/Cocoa/Plug-Ins/Template Editor/English.lproj/TemplateWindow.nib/classes.nib index f12514d..ba2a511 100644 --- a/Cocoa/Plug-Ins/Template Editor/English.lproj/TemplateWindow.nib/classes.nib +++ b/Cocoa/Plug-Ins/Template Editor/English.lproj/TemplateWindow.nib/classes.nib @@ -4,7 +4,7 @@ { CLASS = TemplateWindowController; LANGUAGE = ObjC; - OUTLETS = {fieldsMatrix = NSMatrix; }; + OUTLETS = {containerView = NSView; }; SUPERCLASS = NSWindowController; } ); diff --git a/Cocoa/Plug-Ins/Template Editor/English.lproj/TemplateWindow.nib/info.nib b/Cocoa/Plug-Ins/Template Editor/English.lproj/TemplateWindow.nib/info.nib index afa3a5b..5693dad 100644 --- a/Cocoa/Plug-Ins/Template Editor/English.lproj/TemplateWindow.nib/info.nib +++ b/Cocoa/Plug-Ins/Template Editor/English.lproj/TemplateWindow.nib/info.nib @@ -3,10 +3,26 @@ IBDocumentLocation - 672 193 356 240 0 0 1600 1002 + 276 97 356 240 0 0 1024 746 + IBEditorPositions + + 22 + 114 377 480 236 0 0 1024 746 + 45 + 163 366 480 162 0 0 1024 746 + IBFramework Version - 286.0 + 283.0 + IBLockedObjects + + 20 + 19 + + IBOpenObjects + + 5 + IBSystem Version - 6D52 + 6G30 diff --git a/Cocoa/Plug-Ins/Template Editor/English.lproj/TemplateWindow.nib/objects.nib b/Cocoa/Plug-Ins/Template Editor/English.lproj/TemplateWindow.nib/objects.nib index 8704de2..90568e5 100644 Binary files a/Cocoa/Plug-Ins/Template Editor/English.lproj/TemplateWindow.nib/objects.nib and b/Cocoa/Plug-Ins/Template Editor/English.lproj/TemplateWindow.nib/objects.nib differ diff --git a/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.h b/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.h index 944001b..dddedaa 100644 --- a/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.h +++ b/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.h @@ -5,7 +5,7 @@ @interface TemplateWindowController : NSWindowController { - IBOutlet NSMatrix *fieldsMatrix; + IBOutlet NSView *containerView; NSMutableArray *tmpl; NSMutableArray *res; diff --git a/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.m b/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.m index a39b017..a1cfe4b 100644 --- a/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.m +++ b/Cocoa/Plug-Ins/Template Editor/TemplateWindowController.m @@ -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] ); } } } diff --git a/NovaTools/DataSource.m b/NovaTools/DataSource.m index 9db886b..3fbdfa8 100755 --- a/NovaTools/DataSource.m +++ b/NovaTools/DataSource.m @@ -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; } diff --git a/NovaTools/NovaWindowController.m b/NovaTools/NovaWindowController.m index cc4848a..6b6eae6 100644 --- a/NovaTools/NovaWindowController.m +++ b/NovaTools/NovaWindowController.m @@ -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] ) { diff --git a/NovaTools/Structs.h b/NovaTools/Structs.h index fc2e22d..98bc34e 100644 --- a/NovaTools/Structs.h +++ b/NovaTools/Structs.h @@ -2,6 +2,10 @@ #import +#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; \ No newline at end of file +} IntfRec; + +#pragma options align=reset \ No newline at end of file diff --git a/NovaTools/boom/BoomWindowController.h b/NovaTools/boom/BoomWindowController.h index 107b8a2..6463047 100644 --- a/NovaTools/boom/BoomWindowController.h +++ b/NovaTools/boom/BoomWindowController.h @@ -1,12 +1,18 @@ #import #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 diff --git a/NovaTools/boom/BoomWindowController.m b/NovaTools/boom/BoomWindowController.m index 2bf4ff6..0076b62 100644 --- a/NovaTools/boom/BoomWindowController.m +++ b/NovaTools/boom/BoomWindowController.m @@ -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 diff --git a/NovaTools/boom/English.lproj/boom.nib/info.nib b/NovaTools/boom/English.lproj/boom.nib/info.nib index 3cb3257..3517477 100644 --- a/NovaTools/boom/English.lproj/boom.nib/info.nib +++ b/NovaTools/boom/English.lproj/boom.nib/info.nib @@ -1,16 +1,16 @@ - - + + IBDocumentLocation - 161 150 356 240 0 0 1600 1002 + 86 100 356 240 0 0 1024 746 IBFramework Version - 248.0 + 283.0 IBOpenObjects 5 IBSystem Version - 5S66 + 6G30 diff --git a/NovaTools/boom/English.lproj/boom.nib/objects.nib b/NovaTools/boom/English.lproj/boom.nib/objects.nib index 663b5b6..14eb620 100644 Binary files a/NovaTools/boom/English.lproj/boom.nib/objects.nib and b/NovaTools/boom/English.lproj/boom.nib/objects.nib differ diff --git a/NovaTools/char/CharWindowController.h b/NovaTools/char/CharWindowController.h index 775d390..64a00d9 100644 --- a/NovaTools/char/CharWindowController.h +++ b/NovaTools/char/CharWindowController.h @@ -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; diff --git a/NovaTools/char/CharWindowController.m b/NovaTools/char/CharWindowController.m index bd3712b..fd56035 100644 --- a/NovaTools/char/CharWindowController.m +++ b/NovaTools/char/CharWindowController.m @@ -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 )[NSClassFromString(@"Resource") getResourceOfType:[plugBundle localizedStringForKey:@"desc" value:@"" table:@"Resource Types"] andID:introText inDocument:nil] data]; + if( stringData != nil ) { - const char *stringData = [[(id )[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 )[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 )[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 )[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 )[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 diff --git a/NovaTools/char/English.lproj/char.nib/classes.nib b/NovaTools/char/English.lproj/char.nib/classes.nib index e78b3e8..4e957ab 100644 --- a/NovaTools/char/English.lproj/char.nib/classes.nib +++ b/NovaTools/char/English.lproj/char.nib/classes.nib @@ -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; diff --git a/NovaTools/char/English.lproj/char.nib/info.nib b/NovaTools/char/English.lproj/char.nib/info.nib index c7ca465..ddf632d 100644 --- a/NovaTools/char/English.lproj/char.nib/info.nib +++ b/NovaTools/char/English.lproj/char.nib/info.nib @@ -1,11 +1,11 @@ - - + + IBDocumentLocation - 47 148 356 240 0 0 1600 1002 + 308 330 356 240 0 0 1024 746 IBFramework Version - 248.0 + 283.0 IBGroupedObjects 2 @@ -20,11 +20,7 @@ IBLastGroupID 3 - IBOpenObjects - - 137 - IBSystem Version - 5S66 + 6G30 diff --git a/NovaTools/char/English.lproj/char.nib/objects.nib b/NovaTools/char/English.lproj/char.nib/objects.nib index 62abb7d..1e2af84 100644 Binary files a/NovaTools/char/English.lproj/char.nib/objects.nib and b/NovaTools/char/English.lproj/char.nib/objects.nib differ diff --git a/ResKnife.pbproj/project.pbxproj b/ResKnife.pbproj/project.pbxproj index 2eb2830..e98dcc4 100644 --- a/ResKnife.pbproj/project.pbxproj +++ b/ResKnife.pbproj/project.pbxproj @@ -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