-setPosition:ofDividerAtIndex: for Mac OS X 10.4?

Although Mac OS X 10.5 is mainstream OS X nowadays, I don’t think it is the time to abandon 10.4 yet. 10.4 is pretty stable OS and there can be lots of people who still uses 10.4. Especially many employees for a company can still use 10.4.

So, I’m trying to write my code as much compatible with 10.4 as possible.

However, some sophisticate classes like NSOutlineView, NSSplitView on 10.4 don’t have convenient but very essential messages or ways of manipulating items inside of such container classes.

One example in NSSplitView is -setPosition:ofDividerAtIndex:.
It is not easy to find out what messages can be used to set a divider’s position for pre-OS X 10.5, and Apple’s document doesn’t explain much about the NSSplitView. So, on my iMac 17″, which has OS X 10.4, I read the document carefully and got a clue.
Overall idea is like this.

  1. resize each sub view using -setFrame. For example, you should resize a top frame and a bottom frame for an NSSplitView which is splitted horizontally. (top/down).
  2. draw a divider by calling -drawDividerInRect. To figure out the thickness of a divider, -dividerThickness should be called.
  3. call -adjustSubviews for the sub views to fit an NSSplitView. It also refreshes. So, any visual glitch will go away.
- (IBAction)moveDividerDown: (id)sender
{
	id topView = [[mSplitView subviews] objectAtIndex:0];
	id bottomView = [[mSplitView subviews] objectAtIndex:1];

	NSRect topViewFrameRect = [topView frame];
	displayRect( @"^^ topViewFrameRect ^^", topViewFrameRect );

	NSRect bottomViewFrameRect = [bottomView frame];
	displayRect( @"VV bottomViewFrameRect VV", bottomViewFrameRect );

    if( bottomViewFrameRect.size.height >= 20 )
    {
        topViewFrameRect.size.height += 10.0f;
        [topView setFrame:topViewFrameRect];
        displayRect( @"^^ topViewFrameRect ^^", [topView frame] );

        bottomViewFrameRect.size.height -= 10.0f;
        [bottomView setFrame:bottomViewFrameRect];
        displayRect( @"VV bottomViewFrameRect VV", [bottomView frame] );

        [mSplitView drawDividerInRect:NSMakeRect(bottomViewFrameRect.origin.x, bottomViewFrameRect.size.height,
            bottomViewFrameRect.size.width,
            [mSplitView dividerThickness] )];

        [mSplitView adjustSubviews];
    }
}

- (IBAction)moveDividerUp: (id)sender
{
	id topView = [[mSplitView subviews] objectAtIndex:0];
	id bottomView = [[mSplitView subviews] objectAtIndex:1];

	NSRect topViewFrameRect = [topView frame];
	displayRect( @"^^ topViewFrameRect ^^", topViewFrameRect );

	NSRect bottomViewFrameRect = [bottomView frame];
	displayRect( @"VV bottomViewFrameRect VV", bottomViewFrameRect );

    if( topViewFrameRect.size.height >= 20 )
    {
        topViewFrameRect.size.height -= 10.0f;
        [topView setFrame:topViewFrameRect];
        displayRect( @"^^ topViewFrameRect ^^", [topView frame] );

        bottomViewFrameRect.size.height += 10.0f;
        [bottomView setFrame:bottomViewFrameRect];
        displayRect( @"VV bottomViewFrameRect VV", [bottomView frame] );

        [mSplitView drawDividerInRect:NSMakeRect(bottomViewFrameRect.origin.x, bottomViewFrameRect.size.height,
                                                 bottomViewFrameRect.size.width,
                                                 [mSplitView dividerThickness] )];

        [mSplitView adjustSubviews];
    }
}

Because the coordinated system for the NSSplitView is flipped, the moveDividerUp button event handler can be implemented simply as shown above.

The sample code above is for this visual orientation.
How to move position of a divider of an NSSplitView with 10.4 SDK

One more thing to mention.
The behaviour on Mac OS X 10.5 machine and 10.4 machine is somewhat different.
On 10.5 machine, if the size of top view is changed, the divider moves and its bottom view seems to be moved.
( I only took a glace at it. So, I can be wrong. )
Even though same 10.4 SDK is used, the behaviour is different. ( I noticed this kind of problem a few times. ) So, it is better to test on a 10.4 machine for being sure.

P.S. This code is a utility function used in the code sample above.

void displayRect( NSString *msg, NSRect theRect )
{
	NSLog(@"[%@]\n Origin = { %f, %f}\n Size = { %f, %f }", msg,
		  theRect.origin.x, theRect.origin.y,
		  theRect.size.width, theRect.size.height );
}

P.S. Sometimes, the divider dimple can appear on unexpected location of a window on which the divider is being drawn. To get rid of the ghost dimple, you can issue this right after drawDividerInRect call.

[[[NSApp mainWindow] contentView] setNeedsDisplay:YES];

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: