REALLY custom About box

We’ve all seen (and probably implemented) About Boxes in our applications. The standard About Box provides a great bang for the effort (almost none), but the window isn’t resizeable, and the icon could be a smidge larger… and there doesn’t appear to have a way of modifying it.

I have (finally!!!) managed to get a richt text file (Credits.rtf) to display in a custom about box. Actually, I managed to get a .rtfd that has pictures to display. There is still a slight problem with an error if the custom “call method” isn’t inside a try block, but… since I tried for so long to get this to work, I imagine others could find it useful as well. It involves a bit of Cocoa to make the magic happen as I couldn’t do it with pure call methods.

The obvious side-effect of this is increased complexity. You could try and adapt this to a pre-existing application you might have (work on a copy of it just to be sure - after all, I’m pretty new at this too!):

Select “New File” from the Xcode File menu and choose a Cocoa Objective-C class (and check the box that says “also create xxx.h file” in your active target. Give it any name (in this example I used AboutRTFDCredits.m).

For AboutRTFDCredits.h:


#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import <AppKit/NSAttributedString.h>

@interface NSApplication (ASKARFTDCredits)

// this custom method "setRTFDView:textview:" takes 2 parameters
// a POSIX path to where the Credits.rtfd file is located inside the application
//
// and a text view where the .rtfd file will be placed

- (void)setRTFDView:(NSString *)creditsPath textview:(NSTextView *)textView;

@end

For AboutRTFDCredits.m:



#import "AboutRTFDCredits.h"

@implementation NSApplication (ASKARFTDCredits)

// this cocoa implementation will interpret a Credits.rtfd file and display it in a text view

- (void)setRTFDView:(NSString *)creditsPath textview:(NSTextView *)textView
{
	//An AttributedSting holds a string formatted with font information
	NSAttributedString *creditsString;

	//loads the Credits.rtfd from the main bundle passed in the AS call method
	creditsString = [[NSAttributedString alloc]
		initWithPath: creditsPath documentAttributes: (NSDictionary **) NULL];

	//Fills the text view passed in the call method
	[textView replaceCharactersInRange:NSMakeRange( 0, 0 )
			withRTFD:[creditsString RTFDFromRange:
			NSMakeRange( 0, [creditsString length] )
						documentAttributes:nil]];
}

@end


For the custom about box, create a new .nib in Interface Builder. It’s best to separate these nibs as the AboutBox isn’t going to be called but every once in a while (mostly by the developer - they can be so vain), so no need to load it in general use.

Create a new window. Set up the icon by placing a NSImage, and setting the Attribute in the info panel to “NSApplicationIcon” (scale size appropriately). You may need to go back and do this AFTER the .nib file has been added to your project, because the custom icon comes from MainMenu.nib - or the project itself).

Then set down 3 “System Label Font Text” sections. Delete the contents of them so they are blank. Give them an applescript name so that we can change them in the code. (The three names used below were “AppName”, “AppNameVersion” & “AppCopyright”). This information is obtained from the Info.plist file in Project Builder that every app has. So if you are looking to change the values in the window, the Info.plist file is where to change them.

Set down a NSTextView, give it an applescript name (here it’s called “AboutApp”). Give the scroll view the same name.

Save the nib as “AboutPanel.nib” and add it to your project

Back in your main application, add an Applescript name for the “About xxx” menu item, and make sure that the “on choose menu item” handler is checked. Name it “AboutPanel”.

Then, for the Applescript code itself:

on choose menu item theObject
	set menu_name to the name of theObject
	if menu_name is "AboutPanel" then

		-- this will load the .nib file
		load nib "AboutPanel"

		-- this sets up retrieving/setting information for the application
		set the_main_bundle to call method "mainBundle" of class "NSBundle"
		
		-- the parameters come from the Info.plist file
		set app_name to call method "objectForInfoDictionaryKey:" of the_main_bundle with parameters {"CFBundleName"}
		set app_version to call method "objectForInfoDictionaryKey:" of the_main_bundle with parameters {"CFBundleShortVersionString"}
		set app_copyright to call method "objectForInfoDictionaryKey:" of the_main_bundle with parameters {"NSHumanReadableCopyright"}
		
		-- Your "main" window may be called something else
		display window "AboutPanel" attached to window "main"
		
		set contents of text field "AppName" of window "AboutPanel" to app_name as string
		set contents of text field "AppNameVersion" of window "AboutPanel" to app_version as string
		set contents of text field "AppCopyright" of window "AboutPanel" to app_copyright as string

		-- sets the POSIX path to the Credit.rtfd file buried in the application bundle
		set credits_rtfd_path to call method "pathForResource:ofType:" of the_main_bundle with parameters {"Credits", "rtfd"}
		
		tell text view "AboutApp" of scroll view "AboutApp" of window "AboutPanel"
			try
				-- this sets the text view to the Credits.rtfd file using the custom Cocoa method
				set contents to call method "setRTFDView:textview:" with parameters {credits_rtfd_path, (text view "AboutApp" of scroll view "AboutApp" of window "AboutPanel")}
			end try
		end tell
	end if
end choose menu item


Create a Credits.rtfd file (you can make it in TexEdit as a simply formated text document with whatever typefaces you want, and then add a picture). What’s important is the filename and type. Take the Credits.rtfd file, and add it to your Applescript Studio project - make sure to check the boxes for Copying to the Target.

Compile and choose About this application from the menu. You probably want to add an okay button on that panel to close the window, because you have to Force Quit it for now, but that doesn’t take a whole lot extra.


Note: this is set up for a Credits.rtfd file that contains pictures. It can be easily adapted to a simple Credits.rtf file that uses text ONLY. The “setRTFDView:textview:” in the try block calls the Cocoa implementation above, but you can change it to set up for a picture-less Credits.rtf file. A few changes are in order to adapt it:

Cocoa files: change “setRTFDView” to “setRTFView” (just for descriptive-ness)
Cocoa AboutRTFDCredits.m file: change “withRTFD:[creditsString RTFDFromRange:”
to “withRTFF:[creditsString RTFFFromRange:”
Applescript source: change {“Credits”, “rtfd”} to {“Credits”, “rtf”}
Applescript source: change “setRTFDView:textview:” to “setRTFView:textview:”

Any why can’t the method “setRTFDView:textview:” be found in Apple’s documentation? Because one doesn’t exist (or at least I don’t think it exists). It’s a custom method created after trying to make get a text box filled with a .rtf file. In pouring over Apple’s mailing lists, I adapted a method for HTMLView in combination with an article at cocoadev for a scrolling about box (http://cocoadevcentral.com/articles/000044.php). And now we too can have nice About boxes.

Hope you get some good mileage out of it! I hope I explained it well enough - I was creaming in my pants after it worked (it takes so little apparently).

Here’s an example: http://members.verizon.net/pucklock/SpiffyAboutBox.pdf

sounds awesome, i’ll check it out.

:stuck_out_tongue: :stuck_out_tongue: :stuck_out_tongue: :shock:

Doesn’t any “Credits.rtf” or “Credits.rtfd” show up in the about box anyway just from putting it in the project? That’s what I usually do.

In addition, i tried this and got 80 "error: stray ‘240’ in program"s and "error: stray ‘302’ in program"s

i don’t know what i did wrong here

I learned this today in fact.

the /302’s are hidden characters that came along with whatever you copied and pasted, you can pull them out in BBedit or you can type the code in manually

:shock:

umm… i think the 302’s are spaces. i think what happens is they are somehow different than the spaces that project builder uses. so, what you can do is just copy/paste the whole thing, then delete the spaces and re-enter them in manually. the 240’s might be tabs.

Has any one figured out how to get around having to force quit? I tried the “OK” button but that doesn’t seem to help.

Well, that skips over the whole “You have to create a named button in InterfaceBuilder.app” part

Start by opening your project in Xcode (that’s right, its easiest - and if you have pictures, the BEST way).
You will see at least 1 nib (maybe more) on the left of your project; you’ll see your files and… junk. Under the “Resources” folder (where your File.rtf should be), you’ll see some *.nib files (standard issue is “MainMenu.nib”). Double-click on that to open the nib in InterfaceBuilder.

¢ In InterfaceBuilder, from the top menu, choose “Tools → Show Inspector”
¢ In InterfaceBuilder, there will be a window on the bottom called “MainMenu.nib (xxx)”, and some window names. Open your “About” window.
¢ In InterfaceBuilder, select the button (your “OK” button) - it will bet blue highlight circles around it. In the Inspector info window, there is a pop-up menu up top next to the puce colored (well, maybe not puce, but whatever). Select “Applescript” there. On the bottom will be an unchecked checkbox and the name(s) of your script. Select which ever one script will be handling the click, and check the box. Now in the “Event Handlers” section, under “Action” select the “clicked” checkbox.

¢ In InterfaceBuilder, save the nib (Command-S), and go back to Xcode.

Your project may now have a new “on clicked theObject” handler. So to handle the closing of the window:

on clicked theObject
 if (name of theObject is "CloseAbout") then
		close panel (window of theObject) --this may be different based on what type of window or panel you have
end clicked 

Buttons don’t divine your intentions. What, you were thinking if a button were named “Million Bucks in my pocket” it would… wait, lemme try… nope. Still dirt poor.

BTW, I don’t use that code anymore. Here is what I now use:

	on ShowHelp()
		show window "Help"
		set QuickHelp_rtfd_path to call method "pathForResource:ofType:" of main bundle with parameters {"QuickHelp", "rtfd"}
		call method "readRTFDFromFile:" of object (text view "Help" of scroll view "Help" of window "Help") with parameter QuickHelp_rtfd_path
	end ShowHelp

toodles

For macsig I just added Credits.html to the project (made it localizable if that matters), and here’s the result on Tiger: http://pcheese.net/external/macsigaboutboxhtml.png

On Panther, the CSS doesn’t work.