Seagull 3 Public Beta 9 Now Available

January 12th, 2006

Please be aware that this version can not open library files created with previous beta versions.

  • Fixed a bug that made it difficult to resize the video player window when the playlist was set to preserve the aspect ratio.
  • Fixed a bug in the professional version that prevented the audio from being output after the first video.
  • You can now join multiple videos together.
  • Smart playlists can now have multiple rules.
  • The View Options dialog is now available and it allows you to customize which columns to display in the list view.
  • Added buttons to the video player window, which will allow you to send feedback to the video creator, or visit the website associated with that video.
  • Fixed a bug that caused a video’s star rating to occasionally be saved as one star less than desired.
  • Fixed a bug that made it difficult to select the desired star rating for a video, depending on the width of the rating column.
  • If you have the preferences configured to delete viewed vidcasts after they have been played, then that is now done.
  • In the professional version, the video output settings can now be set for each playlist. They were previously global settings.
  • In the professional version, you can now change the video output settings without having to turn output on and off first.
  • In the professional version, the application now waits five seconds before beginning output in order to give external devices time to prepare, and so that no frames are lost.
  • The join movie feature now removes all of the movies from the library, and replaces them with a reference movie, which makes it work extremely fast. It also makes a guess as to what the file name of the reference movie should be.
  • Disabled full screen playback and view size changing when outputting to a device.
  • Fixed a bug that caused the video player to be placed in the wrong position on the window, when returning from full screen playback.
  • The controller no longer disappears when coming out of full screen.
  • The cursor shows up sooner when coming out of full screen.
  • Fixed the fraction of a second display on the status view.
  • In the professional version, fixed a bug that prevented the video output mode details from being displayed for the selected mode.
  • In the professional version, fixed a bug in the way the refresh rate is displayed.
  • Fixed a bug that occurred when an existing library was set to automatically open, but it could not be found. A half blank document appeared. Now, if the existing library can’t be found, a new library is opened.
  • Resizing of the player window is now animated.
  • Fixed a drawing problem in the rack view. When the thumbnail was taller than it was wide, it was not placed inside the television correctly. Improved centering of the thumbnail in the tv.

You can download Seagull 3 from here:

http://www.trinfinitysoftware.com/seagull.shtml

Rating Style NSLevelIndicatorCell Quirkiness

January 12th, 2006

I have noticed two quirks in the NSLevelIndicatorCell for star ratings. The first is that when you click on them, the star that becomes selected has nothing to do with which star you clicked, but rather the horizontal position of the cursor within the cell when you clicked. If your Ratings column is wider than the stars that are displayed, you will have to click the rightmost section of the cell, which is no where near the stars, to select the highest star rating. This is completely unacceptable for a commercial application, so to fix it make sure your Ratings NSTableColumn has a fixed size, that is as close to the with of the stars as possible. For a cell with a maximum of five stars, a maximum and minimum width of 68 seems to work well.

The second quirk alludes to the cause of the first. The quirk is that the value for that cell is stored as a double, rather than as an integer. This doesn’t seem to make sense at first, given that you can’t have a half star rating, or any other fraction of a star rating. The reason for this anomaly is that the other styles of NSLevelIndicatorCell can display fractional widths. With this information in hand, I deduced that the first quirk is also present because of the way the other styles work. They display in the entire width of the cell, unlike the ratings style, and the cell computes the new value using the horizontal position of the click as a fraction of the maximum value allowed for the cell.

If you use a double to store this information in your files, you won’t have any problems. However, a double value is inappropriate for actually using the rating information in your application. As an example, one of our applications (Seagull 3), allows the user to create smart playlists. If the user were to create a smart playlist looking for all of the videos with a five star rating, the only results that would be returned would be the ones whose rating equaled 5.0 exactly. The NSLevelIndicatorCell shows five stars for any value between 4.50 and 5.49, or if five is the maximum number of stars, any value greater than 4.50.

Another problem occurs when using bindings and CoreData with the ratings style NSLevelIndicatorCell. If your rating property is an integer, the bindings system will simply drop the mantissa (the part of the number after the decimal point), instead of rounding it off, which will cause some ratings to drop by one star when you save. In order to solve this, I created a simple NSValueTransformer subclass, which can be used with the bindings system to round off the mantissa in the same way that the NSLevelIndicatorCell does.

#import "TSDoubleToIntegerRounder.h"

@implementation TSDoubleToIntegerRounder

+ (Class)transformedValueClass
{
return [NSNumber self];
}

+ (BOOL)allowsReverseTransformation
{
return YES;
}

// Round the double down if less than .50 and round it up if greater than or equal to .50.
- (id)transformedValue:(id)aNumber
{
double mantissa = [aNumber doubleValue] - [aNumber intValue];
int result = (mantissa >= 0.50 ? [aNumber intValue] + 1 : [aNumber intValue]);
return [NSNumber numberWithInt:result];
}

- (id)reverseTransformedValue:(id)aNumber
{
double mantissa = [aNumber doubleValue] - [aNumber intValue];
int result = (mantissa >= 0.50 ? [aNumber intValue] + 1 : [aNumber intValue]);
return [NSNumber numberWithInt:result];
}

@end

In Interface Builder, select the NSLevelIndicatorCell, and go to the Bindings section in the Inspector window. Then enter “DoubleToIntegerRounder” in the Value Transformer combo box.

You must remember to register this value transformer in the initialize method of your application’s delegate class, using the following code.


TSDoubleToIntegerRounder *doubleToIntRounder;
doubleToIntRounder = [[[TSDoubleToIntegerRounder alloc] init] autorelease];
[NSValueTransformer setValueTransformer:doubleToIntRounder forName:@"DoubleToIntegerRounder"];

Hiding NSTableColumns

January 9th, 2006

I recently had the displeasure of realizing that NSTableColumns do not have a setHidden: method, nor do they have any other simple means of hiding them. I turned to my favorite Cocoa development sites (cocoadev.com, cocoabuilder.com ) in search for a way to accomplish this. I found a number of other people asking the same question I had, and the responses were always something like, “You just have to create your columns dynamically.” This means that because of a single missing feature, I was going to lose all of the simplicity, convenience, and time-saving of using Interface Builder to create this interface element. Defeated, and depressed, I ventured off into Xcode to start writing code to create my twenty four different columns, each using different data cells, formatters, alignment, etc.

After a couple hours of cursing this chink in Cocoa’s armor, I thought that this couldn’t be right. There is no reason that I should be writing all of this code. Someone must have encountered this problem before. Someone must have a better solution. So I went back to searching the web, and found a single small comment by the stupendous mmalc (mmalcolm Crawford) which revealed the answer. Let Interface Builder create the columns, cache them, and then repopulate the table as appropriate. I was right. There was no need to create the columns dynamically, and if I hadn’t simply accepted the answers I read earlier, I might have thought of the solution myself.

Since I was unable to find any sample code to solve this problem, I decided to release the code I created. First, you have to design your table columns in Interface Builder. Next, add this line of code to your project in a method that gets called after the nib file is loaded, such as awakeFromNib:, or windowControllerDidLoadNib:. This code saves the table’s array of columns in a class property (theTableColumns).


theTableColumns = [[NSArray alloc] initWithArray:[theTable tableColumns] copyItems:NO];

You may be tempted to pass YES for the copyItems: parameter in order to actually duplicate each of the NSTableColumns (I was), but don’t. NSTableColumns don’t support the NSCopying protocol, so you will get an exception when NSArray tries to call copyWithZone: on them. It is also unnecessary to make a duplicate of each NSTableColumn, and would result in wasted memory. You need to use NSArray’s initWithArray:copyItems: method, instead of something simpler like arrayWithArray:, because this method sends a retain message to each of the items in the array, and arrayWithArray: does not. We need to keep these NSTableColumns around even after they have been removed from the NSTableView.

Here is the code to setup the columns. I call this method once after the nib has been loaded (and the table columns have been cached), and then after each time the user changes which columns they want shown. I have edited the code a bit to make the variable names generic, to add comments for additional clarity, and to remove any code that is irrelevant to what I am demonstrating.


- (void)setupColumns
{
// Remove all of the existing columns from the table.
while( [theTable numberOfColumns] > 0 )
[theTable removeTableColumn:[[theTable tableColumns] objectAtIndex:0]];

// Make sure we have cached columns to add back in.
if( !theTableColumns ) return;

// Add back any of the columns that the user wants to see.
NSEnumerator *columnEnumerator = [theTableColumns objectEnumerator];
NSTableColumn *nextColumn;
while( nextColumn = [columnEnumerator nextObject] )
{
NSString *identifier = [nextColumn identifier];
if( identifier && ![identifier isEqualToString:@""] && [self showColumn:identifier]) [theTable addTableColumn:nextColumn];
}
}

You will need to implement the showColumn: method yourself, as appropriate for your application. Here is the method signature:


- (void)showColumn:(NSString *)identifier;

The largest benefit of this approach is that it allows you to create all of your columns in Interface Builder, which will save you a lot of time. It’s also a very small amount of code, which makes it easier for everyone to understand, debug, and maintain. This approach will also preserve the order of the columns as they were designed in IB.

Don’t forget to release the columns and array when you are done with them.


- (void)dealloc
{
if( listViewTableColumns )
{
[theTableColumns makeObjectsPerformSelector:@selector(release)];
[theTableColumns release];
}
[super dealloc];
}

The next step is to investigate whether or not this approach will prevent the size of each column from being saved to the user defaults.

I hope you have found this helpful, and please feel free to leave any corrections or suggestions in the comments section.

Finish Our Palm OS Game

December 9th, 2005

We had been developing an expansive, non-linear, adventure game for the Palm OS, which was similar to the original Legend of Zelda for the Nintendo Entertainment System, but more important projects had to take priority, so we put the project on hold. The one year anniversary of its shelving, December 15th, is fast approaching, and we realized that we aren’t going to be able to finish it anytime soon. Rather than let it collect dust in obscurity, we decided to release the entire project, source code included, under a creative commons license, which means you can download the source code, figure out how it works, learn a bit about programming Palm OS games using MacOS X, make your own game from it, and use it commercially, as long as you give us credit, and release the source code to your game to the public.

The game is called Mort, and you can find out more about it here:
http://www.trinfinitysoftware.com/mort.shtml

Happy Holidays!

Seagull 3 Is A Free Upgrade For All Seagull Video Player 2.x Professional Users

November 18th, 2005

If you are a registered Seagull Video Player Professional user, you will be receiving an update license in your email, within the next couple of days. The latest public beta of Seagull 3 includes the professional features, so we hope that all Seagull Video Player Pro users will download it and give it a try.

You can download Seagull 3 from here:
http://www.trinfinitysoftware.com/seagull.shtml

Please remember that this is a beta version, which means that it may, and probably does, still have some bugs in it. Therefore, we recommend that you keep your current version of Seagull Video Player and its associated files, until the final release of Seagull 3. If you encounter any problems, or if you have have any suggestions for improvement, please send us an email at the appropriate email address.

Bugs: bugs@trinfinitysoftware.com
Feature Requests: featurerequests@trinfinitysoftware.com
Feedback: feedback@trinfinitysoftware.com

Be sure to include the name of the application, in this case Seagull 3, the type of device, and name of the QuickTime Output Component you are using, such as:

Device: Dazzle DV Bridge, Component: Apple Firewire

We would also appreciate it if every pro user would drop us a line, and let us know what type of hardware and components they use. You can send an email to feedback@trinfinitysoftware.com or leave a comment on this post. This will help us to gauge which hardware devices should receive the most attention in development and testing.

Seagull 3 Public Beta 8 Now Available

November 18th, 2005

The Output To Device professional feature is now available, and it is fully functional during the demo period. To send your videos out to a device, such as a digital video bridge, or FireWire-ready DVD recorder, select “Output To Device…” from the “View” menu. After being reminded that you must purchase a professional license to use this feature after the demo period, you will be presented with a dialog, which will allow you to configure the output. Click the “OK” button, and then select “Play” from the “Control” menu, or press the play button on the top of the library window.

This update also includes a Take Snapshot feature, which allows you to save an image to the desktop, which contains the current frame of the movie you are watching.

We have also improved the progress display, which resides on the top of each library window. It now allows you to jump to another point in the current movie by clicking on a point in the timeline. You can also toggle between displaying the time remaining, or the total time in the current movie in the progress display, by clicking on that time.

We have added a Play Count column to the list view, which displays the number of times each video has been played.

We have also improved the filtering out of non-video file formats when downloading content from the Internet.

In addition, if you press any key, other than a command key combination, while in full screen mode, Seagull will exit full screen mode. This is to avoid situations where new users, who don’t know or remember the right keys to press to exit full screen mode, would get stuck in it.

This update also has a number of smaller improvements, and fixes a number of bugs, including:

  • Fixed a bug that caused the application to crash when the user tried to quit while downloading.
  • Fixed a bug that prevented the registrant’s name and email address from being shown immediately after entering their serial number.
  • The Professional Feature dialog that explains to the user that they are about to use a feature of the professional version, is no longer displayed when the user turns off the Output To Device feature.
  • Fixed a bug that caused the QuickTime controller from dissappearing when coming out of full screen mode.
  • When coming out of full screen mode, the cursor is unhidden quicker.
  • Fixed a bug that prevented the user from turning on full screen mode from the menu.
  • Fixed the fraction of a second on the progress display.
  • Fixed a bug that prevented the shuffle and loop features from working properly.

You can download Seagull 3 from here:

http://www.trinfinitysoftware.com/seagull.shtml

Origin of Our Name

November 16th, 2005

Welcome to the first post! As a treat, and to set the record straight, I thought I would share with you the origin of our often-mispelled, often-mispronounced name, Trinfinity Software.

Around 1998, I was reading a novel called White Light by a mathematician named Rudy Rucker. In this novel, he attempts to explain the different levels of infinity. Each level has a different name. Regular infinity is called alef-null, and after that you have alef-one, alef-two, etc. I won’t attempt to explain the distinction between each one because, sadly, I still only have a vague understanding of the concept. If you are interested, I suggest you read the book. It was very enjoyable, and it is not a hard read at all, even if there is a lot of math in it.

Once I learned that there were actually different levels of infinity, I couldn’t get it out of my mind. It popped up in my thoughts for months, as I tried to wrap my head around it. A year later, when I was brainstorming for new names for my new software company (the first name I wanted was BitWise, but it was taken), the idea popped in again. Around this time, a friend told me about someone that had coined the term “threpeat” (Pronounced like 3 Pete) If a repeat is the second time something happens, a threpeat is the third time. I liked the wordplay, and I loved the concept of infinity, so I took the words “Triple Infinity” and combined them into Trinfinity. Say it with me, Trin-Fin-Ity.

By marketing standards, it’s definitely not the best name. It’s not short. It’s a new word, so people are unfamiliar with it, unlike Apple, or Delicious Monster (that name is cool as hell). A lot of people look at it and assume its Trinity Software. Also, I think the frequency of the letters I and N is so high that it just confuses people. But it’s our name, and we’re sticking with it. And it is unique, which is the most important point.