From eeeb6b6828ceff2fd45aea3c6b9f86dc4aa2bde4 Mon Sep 17 00:00:00 2001
From: Matt Tolton <matt@tolton.com>
Date: Mon, 23 Jun 2008 15:57:34 -0700
Subject: [PATCH] Add RBSplitView files.

---
 src/MacVim/RBSplitSubview.h            |  146 +++
 src/MacVim/RBSplitSubview.m            |  927 +++++++++++++++++
 src/MacVim/RBSplitView.h               |  225 +++++
 src/MacVim/RBSplitView.m               | 1734 ++++++++++++++++++++++++++++++++
 src/MacVim/RBSplitViewPrivateDefines.h |   98 ++
 5 files changed, 3130 insertions(+), 0 deletions(-)
 create mode 100644 src/MacVim/RBSplitSubview.h
 create mode 100644 src/MacVim/RBSplitSubview.m
 create mode 100644 src/MacVim/RBSplitView.h
 create mode 100644 src/MacVim/RBSplitView.m
 create mode 100644 src/MacVim/RBSplitViewPrivateDefines.h

diff --git a/src/MacVim/RBSplitSubview.h b/src/MacVim/RBSplitSubview.h
new file mode 100644
index 0000000..d058230
--- /dev/null
+++ b/src/MacVim/RBSplitSubview.h
@@ -0,0 +1,146 @@
+//
+//  RBSplitSubview.h version 1.1.4
+//  RBSplitView
+//
+//  Created by Rainer Brockerhoff on 19/11/2004.
+//  Copyright 2004-2006 Rainer Brockerhoff.
+//	Some Rights Reserved under the Creative Commons Attribution License, version 2.5, and/or the MIT License.
+//
+
+#import <Cocoa/Cocoa.h>
+
+@class RBSplitView;
+
+// These values are used to inquire about the status of a subview.
+typedef enum {
+	RBSSubviewExpanding=-2,
+	RBSSubviewCollapsing=-1,
+	RBSSubviewNormal=0,
+	RBSSubviewCollapsed=1
+} RBSSubviewStatus;
+
+@interface RBSplitSubview : NSView {
+// Subclasses normally should use setter methods instead of changing instance variables by assignment.
+// Most getter methods simply return the corresponding instance variable, so with some care, subclasses
+// could reference them directly.
+	NSString* identifier;			// An identifier string for the subview, default is @"".
+	int tag;						// A tag integer for the subview, default is 0.
+	float minDimension;				// The minimum dimension. Must be 1.0 or any larger integer.
+	float maxDimension;				// The maximum dimension. Must be at least equal to the minDimension.
+									// Set to a large number if there's no maximum.
+	double fraction;				// A fractional part of the dimension, used for proportional resizing.
+									// Normally varies between -0.999... and 0.999...
+									// When collapsed, holds the proportion of the RBSplitView's dimension
+									// the view was occupying before collapsing.
+	NSRect previous;				// Holds the frame rect for the last delegate notification.
+	NSSize savedSize;				// This holds the size the subview had before it was resized beyond
+									// its minimum or maximum limits. Valid if notInLimits is YES.
+	unsigned int actDivider;		// This is set temporarily while an alternate drag view is being dragged.
+	BOOL canDragWindow;				// This is set temporarily during a mouseDown on a non-opaque subview.
+	BOOL canCollapse;				// YES if the subview can be collapsed.
+	BOOL notInLimits;				// YES if the subview's dimensions are outside the set limits.
+}
+
+// This class method returns YES if some RBSplitSubview is being animated.
++ (BOOL)animating;
+
+// This is the designated initializer for creating extra subviews programmatically.
+- (id)initWithFrame:(NSRect)frame;
+
+// Returns the immediately containing RBSplitView, or nil if there is none.
+// couplingSplitView returns nil if we're a non-coupled RBSplitView.
+// outermostSplitView returns the outermost RBSplitView.
+- (RBSplitView*)splitView;
+- (RBSplitView*)couplingSplitView;
+- (RBSplitView*)outermostSplitView;
+
+// Returns self if we're a RBSplitView, nil otherwise. Convenient for testing or calling methods.
+// coupledSplitView returns nil if we're a non-coupled RBSplitView.
+- (RBSplitView*)asSplitView;
+- (RBSplitView*)coupledSplitView;
+
+// Sets and gets the coupling between the view and its containing RBSplitView (if any). Coupled
+// RBSplitViews take some parameters, such as divider images, from the containing view. The default
+// for RBSplitView is YES. However, calling setCoupled: on a RBSplitSubview will have no effect,
+// and isCoupled will always return false.
+- (void)setCoupled:(BOOL)flag;
+- (BOOL)isCoupled;
+
+// Returns YES if the containing RBSplitView is horizontal.
+- (BOOL)splitViewIsHorizontal;
+
+// Returns the number of subviews. Just a convenience method.
+- (unsigned)numberOfSubviews;
+
+// Sets and gets the tag.
+- (void)setTag:(int)theTag;
+- (int)tag;
+
+// Sets and gets the identifier string. Will never be nil.
+- (void)setIdentifier:(NSString*)aString;
+- (NSString*)identifier;
+
+// Position means the subview's position within the RBSplitView - counts from zero left to right
+// or top to bottom. Setting it will move the subview to another position without changing its size,
+// status or attributes. Set position to 0 to move it to the start, or to some large number to move it
+// to the end of the RBSplitView.
+- (unsigned)position;
+- (void)setPosition:(unsigned)newPosition;
+
+// Returns YES if the subview is collapsed. Collapsed subviews are squashed down to zero but never
+// made smaller than the minimum dimension as far as their own subviews are concerned. If the
+// subview is being animated this will return NO.
+- (BOOL)isCollapsed;
+
+// This will return the current status of the subview. Negative values mean the subview is
+// being animated.
+- (RBSSubviewStatus)status;
+
+// Sets and gets the ability to collapse the subview. However, this can be overridden by the delegate.
+- (BOOL)canCollapse;
+- (void)setCanCollapse:(BOOL)flag;
+
+// Tests whether the subview can shrink or expand further.
+- (BOOL)canShrink;
+- (BOOL)canExpand;	
+
+// Sets and gets the minimum and maximum dimensions. They're set at the same time to make sure values
+// are consistent. Despite being floats, they'll always have integer values. The minimum value for the
+// minimum is 1.0. Pass 0.0 for the maximum to set it to some huge number.
+- (float)minDimension;
+- (float)maxDimension;
+- (void)setMinDimension:(float)newMinDimension andMaxDimension:(float)newMaxDimension;
+
+// Call this to expand a subview programmatically. It will return the subview's dimension after
+// expansion.
+- (float)expand;
+
+// Call this to collapse a subview programmatically. It will return the negative
+// of the subview's dimension _before_ collapsing, or 0.0 if the subview can't be collapsed.
+- (float)collapse;
+
+// These calls collapse and expand subviews with animation. They return YES if animation
+// startup was successful.
+- (BOOL)collapseWithAnimation;
+- (BOOL)expandWithAnimation;
+
+// These methods collapse and expand subviews with animation, depending on the parameters.
+// They return YES if animation startup was successful. If resize is NO, the subview is
+// collapsed/expanded without resizing it during animation.
+- (BOOL)collapseWithAnimation:(BOOL)animate withResize:(BOOL)resize;
+- (BOOL)expandWithAnimation:(BOOL)animate withResize:(BOOL)resize;
+
+// Returns the current dimension of the subview.
+- (float)dimension;
+
+// Sets the current dimension of the subview, subject to the current maximum and minimum.
+// If the subview is collapsed, this has no immediate effect.
+- (void)setDimension:(float)value;
+
+// This method is used internally when a divider is dragged. It tries to change the subview's dimension
+// and returns the actual change, collapsing or expanding whenever possible. You usually won't need
+// to call this directly.
+- (float)changeDimensionBy:(float)increment mayCollapse:(BOOL)mayCollapse move:(BOOL)move;
+
+@end
+
diff --git a/src/MacVim/RBSplitSubview.m b/src/MacVim/RBSplitSubview.m
new file mode 100644
index 0000000..97748bf
--- /dev/null
+++ b/src/MacVim/RBSplitSubview.m
@@ -0,0 +1,927 @@
+//
+//  RBSplitSubview.m version 1.1.4
+//  RBSplitView
+//
+//  Created by Rainer Brockerhoff on 19/11/2004.
+//  Copyright 2004-2006 Rainer Brockerhoff.
+//	Some Rights Reserved under the Creative Commons Attribution License, version 2.5, and/or the MIT License.
+//
+
+#import "RBSplitView.h"
+#import "RBSplitViewPrivateDefines.h"
+
+// This variable points to the animation data structure while an animation is in
+// progress; if there's none, it will be NULL. Animating may be very CPU-intensive so
+// we allow only one animation to take place at a time.
+static animationData* currentAnimation = NULL;
+
+@implementation RBSplitSubview
+
+// This class method returns YES if an animation is in progress.
++ (BOOL)animating {
+	return currentAnimation!=NULL;
+}
+
+// This is the designated initializer for RBSplitSubview. It sets some reasonable defaults. However, you
+// can't rely on anything working until you insert it into a RBSplitView.
+- (id)initWithFrame:(NSRect)frame {
+    self = [super initWithFrame:frame];
+	if (self) {
+		fraction = 0.0;
+		canCollapse = NO;
+		notInLimits = NO;
+		minDimension = 1.0;
+		maxDimension = WAYOUT;
+		identifier = @"";
+		previous = NSZeroRect;
+		savedSize = frame.size;
+		actDivider = NSNotFound;
+		canDragWindow = NO;
+	}
+	return self;
+}
+
+// Just releases our stuff when going away.
+- (void)dealloc {
+	[identifier release];
+	[super dealloc];
+}
+
+// These return nil since we're not a RBSplitView (they're overridden there).
+- (RBSplitView*)asSplitView {
+	return nil;
+}
+
+- (RBSplitView*)coupledSplitView {
+	return nil;
+}
+
+// Sets and gets the coupling between a RBSplitView and its containing RBSplitView (if any).
+// For convenience, these methods are also implemented here.
+- (void)setCoupled:(BOOL)flag {
+}
+
+- (BOOL)isCoupled {
+	return NO;
+}
+
+// RBSplitSubviews are never flipped, unless they're RBSplitViews.
+- (BOOL)isFlipped {
+	return NO;
+}
+
+// We copy the opacity of the owning split view.
+- (BOOL)isOpaque {
+	return [[self couplingSplitView] isOpaque];
+}
+
+// A hidden RBSplitSubview is not redrawn and is not considered for drawing dividers.
+// This won't work before 10.3, though.
+- (void)setHidden:(BOOL)flag {
+	if ([self isHidden]!=flag) {
+		RBSplitView* sv = [self splitView];
+		[self RB___setHidden:flag];
+		if (flag) {
+			[sv adjustSubviews];
+		} else {
+			[sv adjustSubviewsExcepting:self];
+		}
+	}
+}
+
+// RBSplitSubviews can't be in the responder chain.
+- (BOOL)acceptsFirstResponder {
+	return NO;
+}
+
+// Mousing down should move the window only for a completely transparent background. This might have
+// unintended side effects in metal windows, so for those you might want to use a background color
+// with a very low alpha (0.01 for instance).
+// This is commented out as I'm still experimenting with it.
+/*- (BOOL)mouseDownCanMoveWindow {
+	RBSplitView* sv = [self asSplitView];
+	if (!sv) {
+		sv = [self couplingSplitView];
+	}
+	return [sv background]==nil;
+	return YES;
+}*/
+
+// This returns the owning splitview. It's guaranteed to return a RBSplitView or nil.
+// You should avoid having "orphan" RBSplitSubviews, or at least manipulating
+// them while they're not inserted in a RBSplitView.
+- (RBSplitView*)splitView {
+	id result = [self superview];
+	if ([result isKindOfClass:[RBSplitView class]]) {
+		return (RBSplitView*)result;
+	}
+	return nil;
+}
+
+// This also returns the owning splitview. It's overridden for nested RBSplitViews.
+- (RBSplitView*)couplingSplitView {
+	id result = [self superview];
+	if ([result isKindOfClass:[RBSplitView class]]) {
+		return (RBSplitView*)result;
+	}
+	return nil;
+}
+
+// This returns the outermost directly containing RBSplitView, or nil.
+- (RBSplitView*)outermostSplitView {
+	id result = nil;
+	id sv = self;
+	while ((sv = [sv superview])&&[sv isKindOfClass:[RBSplitView class]]) {
+		result = sv;
+	}
+	return result;
+}
+
+// This convenience method returns YES if the containing RBSplitView is horizontal.
+- (BOOL)splitViewIsHorizontal {
+	return [[self splitView] isHorizontal];
+}
+
+// You can use either tags (ints) or identifiers (NSStrings) to identify individual subviews.
+// We take care not to have nil identifiers.
+- (void)setTag:(int)theTag {
+	tag = theTag;
+}
+
+- (int)tag {
+	return tag;
+}
+
+- (void)setIdentifier:(NSString*)aString {
+	[identifier autorelease];
+	identifier = aString?[aString retain]:@"";
+}
+
+- (NSString*)identifier {
+	return identifier;
+}
+
+// If we have an identifier, this will make debugging a little easier by appending it to the
+// default description.
+- (NSString*)description {
+	return [identifier length]>0?[NSString stringWithFormat:@"%@(%@)",[super description],identifier]:[super description];
+}
+
+// This pair of methods allows you to get and change the position of a subview (within the split view);
+// this counts from zero from the left or top of the split view.
+- (unsigned)position {
+	RBSplitView* sv = [self splitView];
+	return sv?[[sv subviews] indexOfObjectIdenticalTo:self]:0;
+}
+
+- (void)setPosition:(unsigned)newPosition {
+	RBSplitView* sv = [self splitView];
+	if (sv) {
+		[self retain];
+		[self removeFromSuperviewWithoutNeedingDisplay];
+		NSArray* subviews = [sv subviews];
+		if (newPosition>=[subviews count]) {
+			[sv addSubview:self positioned:NSWindowAbove relativeTo:nil];
+		} else {
+			[sv addSubview:self positioned:NSWindowBelow relativeTo:[subviews objectAtIndex:newPosition]];
+		}
+		[self release];
+	}
+}
+
+// Tests whether the subview is collapsed.
+- (BOOL)isCollapsed {
+	return [self RB___visibleDimension]<=0.0;
+}
+
+// Tests whether the subview can shrink further.
+- (BOOL)canShrink {
+	return [self RB___visibleDimension]>([self canCollapse]?0.0:minDimension);
+}
+
+// Tests whether the subview can expand further.
+- (BOOL)canExpand {
+	return [self RB___visibleDimension]<maxDimension;
+}
+
+// Returns the subview's status.
+- (RBSSubviewStatus)status {
+	animationData* anim = [self RB___animationData:NO resize:NO];
+	if (anim) {
+		return anim->collapsing?RBSSubviewCollapsing:RBSSubviewExpanding;
+	}
+	return [self RB___visibleDimension]<=0.0?RBSSubviewCollapsed:RBSSubviewNormal;
+}
+
+// Tests whether the subview can be collapsed. The local instance variable will be overridden by the
+// delegate method if it's implemented.
+- (BOOL)canCollapse {
+	BOOL result = canCollapse;
+	RBSplitView* sv = [self splitView];
+	if ([sv RB___numberOfSubviews]<2) {
+		return NO;
+	}
+	id delegate = [sv delegate];
+	if ([delegate respondsToSelector:@selector(splitView:canCollapse:)]) {
+		result = [delegate splitView:sv canCollapse:self];
+	}
+	return result;
+}
+
+// This sets the subview's "canCollapse" flag. Ignored if the delegate's splitView:canCollapse:
+// method is implemented.
+- (void)setCanCollapse:(BOOL)flag {
+	canCollapse = flag;
+}
+
+// This expands a collapsed subview and calls the delegate's splitView:didExpand: method, if it exists.
+// This is not called internally by other methods; call this to expand a subview programmatically.
+// As a convenience to other methods, it returns the subview's dimension after expanding (this may be
+// off by 1 pixel due to rounding) or 0.0 if it couldn't be expanded.
+// The delegate should not change the subview's frame.
+- (float)expand {
+	return [self RB___expandAndSetToMinimum:NO];
+}
+
+// This collapses an expanded subview and calls the delegate's splitView:didCollapse: method, if it exists.
+// This is not called internally by other methods; call this to expand a subview programmatically.
+// As a convenience to other methods, it returns the negative of the subview's dimension before
+// collapsing (or 0.0 if it couldn't be collapsed).
+// The delegate should not change the subview's frame.
+- (float)collapse {
+	return [self RB___collapse];
+}
+
+// This tries to collapse the subview with animation, and collapses it instantly if some other
+// subview is animating. Returns YES if animation was started successfully.
+- (BOOL)collapseWithAnimation {
+	return [self collapseWithAnimation:YES withResize:YES];
+}
+
+// This tries to expand the subview with animation, and expands it instantly if some other
+// subview is animating. Returns YES if animation was started successfully.
+- (BOOL)expandWithAnimation {
+	return [self expandWithAnimation:YES withResize:YES];
+}
+
+// These methods collapse and expand subviews with animation, depending on the parameters.
+// They return YES if animation startup was successful. If resize is NO, the subview is
+// collapsed/expanded without resizing it during animation.
+- (BOOL)collapseWithAnimation:(BOOL)animate withResize:(BOOL)resize {
+	if ([self status]==RBSSubviewNormal) {
+		if ([self canCollapse]) {
+			if (animate&&[self RB___animationData:YES resize:resize]) {
+				[self RB___clearResponder];
+				[self RB___stepAnimation];
+				return YES;
+			} else {
+				[self RB___collapse];
+			}
+		}
+	}
+	return NO;
+}
+
+- (BOOL)expandWithAnimation:(BOOL)animate withResize:(BOOL)resize {
+	if ([self status]==RBSSubviewCollapsed) {
+		if (animate&&[self RB___animationData:YES resize:resize]) {
+			[self RB___stepAnimation];
+			return YES;
+		} else {
+			[self RB___expandAndSetToMinimum:NO];
+		}
+	}
+	return NO;
+}
+
+
+// These 3 methods get and set the view's minimum and maximum dimensions.
+// The minimum dimension ought to be an integer at least equal to 1.0 but we make sure.
+// The maximum dimension ought to be an integer at least equal to the minimum. As a convenience,
+// pass in zero to set it to some huge number.
+- (float)minDimension {
+	return minDimension;
+}
+
+- (float)maxDimension {
+	return maxDimension;
+}
+
+- (void)setMinDimension:(float)newMinDimension andMaxDimension:(float)newMaxDimension {
+	minDimension = MAX(1.0,floorf(newMinDimension));
+	if (newMaxDimension<1.0) {
+		newMaxDimension = WAYOUT;
+	}
+	maxDimension = MAX(minDimension,floorf(newMaxDimension));
+	float dim = [self dimension];
+	if ((dim<minDimension)||(dim>maxDimension)) {
+		[[self splitView] setMustAdjust];
+	}
+}
+
+// This returns the subview's dimension. If it's collapsed, it returns the dimension it would have
+// after expanding.
+- (float)dimension {
+	float dim = [self RB___visibleDimension];
+	if (dim<=0.0) {
+		dim = [[self splitView] RB___dimensionWithoutDividers]*fraction;
+		if (dim<minDimension) {
+			dim = minDimension;
+		} else if (dim>maxDimension) {
+			dim = maxDimension;
+		}
+	}
+	return dim;
+}
+
+// Sets the current dimension of the subview, subject to the current maximum and minimum.
+// If the subview is collapsed, this will have an effect only after reexpanding.
+- (void)setDimension:(float)value {
+	RBSplitView* sv = [self splitView];
+	NSSize size = [self frame].size;
+	BOOL ishor = [sv isHorizontal];
+	if (DIM(size)>0.0) {
+// We're not collapsed, set the size and adjust other subviews.
+		DIM(size) = value;
+		[self setFrameSize:size];
+		[sv adjustSubviewsExcepting:self];
+	} else {
+// We're collapsed, adjust the fraction so that we'll have the (approximately) correct
+// dimension after expanding.
+		fraction = value/[sv RB___dimensionWithoutDividers];
+	}
+}
+
+// This just draws the background of a subview, then tells the delegate, if any.
+// The delegate would usually draw a frame inside the subview.
+- (void)drawRect:(NSRect)rect {
+	RBSplitView* sv = [self splitView];
+	NSColor* bg = [sv background];
+	if (bg) {
+		[bg set];
+		NSRectFillUsingOperation(rect,NSCompositeSourceOver);
+	}
+	id del = [sv delegate];
+	if ([del respondsToSelector:@selector(splitView:willDrawSubview:inRect:)]) {
+		[del splitView:sv willDrawSubview:self inRect:rect];
+	}
+}
+
+// We check if the RBSplitView must be adjusted before redisplaying programmatically.
+// if so, we adjust and display the whole RBSplitView.
+- (void)display {
+	RBSplitView* sv = [self splitView];
+	if (sv) {
+		if ([sv mustAdjust]) {
+			[sv display];
+		} else {
+			[super display];
+		}
+	}
+}
+
+// RBSplitSubviews will always resize their own subviews.
+- (BOOL)autoresizesSubviews {
+	return YES;
+}
+
+// This is method is called automatically when the subview is resized; don't call it yourself.
+- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
+	RBSplitView* sv = [self splitView];
+	if (sv) {
+		BOOL ishor = [sv isHorizontal];
+		NSRect frame = [self frame];
+		float dim = DIM(frame.size);
+		float other = OTHER(frame.size);
+// We resize subviews only when we're inside the subview's limits and the containing splitview's limits.
+		animationData* anim = [self RB___animationData:NO resize:NO];
+		if ((dim>=(anim&&!anim->resizing?anim->dimension:minDimension))&&(dim<=maxDimension)&&(other>=[sv minDimension])&&(other<=[sv maxDimension])) {
+			if (notInLimits) {
+// The subviews can be resized, so we restore the saved size.
+				oldBoundsSize = savedSize;
+			}
+// We save the size every time the subview's subviews are resized within the limits.
+			notInLimits = NO;
+			savedSize = frame.size;
+			[super resizeSubviewsWithOldSize:oldBoundsSize];
+		} else {
+			notInLimits = YES;
+		}
+	}
+}
+
+// This method is used internally when a divider is dragged. It tries to change the subview's dimension
+// and returns the actual change, collapsing or expanding whenever possible. You usually won't need
+// to call this directly.
+- (float)changeDimensionBy:(float)increment mayCollapse:(BOOL)mayCollapse move:(BOOL)move {
+	RBSplitView* sv = [self splitView];
+	if (!sv||(fabsf(increment)<1.0)) {
+		return 0.0;
+	}
+	BOOL ishor = [sv isHorizontal];
+	NSRect frame = [self frame];
+	float olddim = DIM(frame.size);
+	float newdim = MAX(0.0,olddim+increment);
+	if (newdim<olddim) {
+		if (newdim<minDimension) {
+// Collapse if needed
+			if (mayCollapse&&[self canCollapse]&&(newdim<MAX(1.0,minDimension*(0.5-HYSTERESIS)))) {
+				return [self RB___collapse];
+			}
+			newdim = minDimension;
+		}
+	} else if (newdim>olddim) {
+		if (olddim<1.0) {
+// Expand if needed.
+			if (newdim>(minDimension*(0.5+HYSTERESIS))) {
+				newdim = MAX(newdim,[self RB___expandAndSetToMinimum:YES]);
+			} else {
+				return 0.0;
+			}
+		}
+		if (newdim>maxDimension) {
+			newdim = maxDimension;
+		}
+	}
+	if ((int)newdim!=(int)olddim) {
+// The dimension has changed.
+		increment = newdim-olddim;
+		DIM(frame.size) = newdim;
+		if (move) {
+			DIM(frame.origin) -= increment;
+		}
+// We call super instead of self here to postpone adjusting subviews for nested splitviews.
+//		[super setFrameSize:frame.size];
+		[super setFrame:frame];
+		[sv RB___setMustClearFractions];
+		[sv setMustAdjust];
+	}
+	return newdim-olddim;
+}
+
+// This convenience method returns the number of subviews (surprise!)
+- (unsigned)numberOfSubviews {
+	return [[self subviews] count];
+}
+
+// We return the deepest subview that's hit by aPoint. We also check with the delegate if aPoint is
+// within an alternate drag view.
+- (NSView*)hitTest:(NSPoint)aPoint {
+	RBSplitView* sv = [self splitView];
+	if ([self mouse:aPoint inRect:[self frame]]) {
+		id delegate = [sv delegate];
+		if ([delegate respondsToSelector:@selector(splitView:dividerForPoint:inSubview:)]) {
+			actDivider = [delegate splitView:sv dividerForPoint:aPoint inSubview:self];
+			if ((int)actDivider<(int)([sv RB___numberOfSubviews]-1)) {
+				return self;
+			}
+		}
+		actDivider = NSNotFound;
+		NSView* result = [super hitTest:aPoint];
+		canDragWindow = ![result isOpaque];
+		return result;
+	}
+	return nil;
+}
+
+// This method handles clicking and dragging in an empty portion of the subview, or in an alternate
+// drag view as designated by the delegate.
+- (void)mouseDown:(NSEvent*)theEvent {
+	NSWindow* window = [self window];
+	NSPoint where = [theEvent locationInWindow];
+	if (actDivider<NSNotFound) {
+// The mouse down was inside an alternate drag view; actDivider was just set in hitTest.
+		RBSplitView* sv = [self splitView];
+		NSPoint point = [sv convertPoint:where fromView:nil];
+		[[RBSplitView cursor:RBSVDragCursor] push];
+		NSPoint base = NSZeroPoint;
+// Record the current divider coordinate.
+		float divc = [sv RB___dividerOrigin:actDivider];
+		BOOL ishor = [sv isHorizontal];
+		[sv RB___setDragging:YES];
+// Loop while the button is down.
+		while ((theEvent = [NSApp nextEventMatchingMask:NSLeftMouseDownMask|NSLeftMouseDraggedMask|NSLeftMouseUpMask untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:YES])&&([theEvent type]!=NSLeftMouseUp)) {
+// Set up a local autorelease pool for the loop to prevent buildup of temporary objects.
+			NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+			NSDisableScreenUpdates();
+// This does the actual movement.
+			[sv RB___trackMouseEvent:theEvent from:point withBase:base inDivider:actDivider];
+			if ([sv mustAdjust]) {
+// If something changed, we clear fractions and redisplay.
+				[sv RB___setMustClearFractions];
+				[sv display];
+			}
+// Change the drag point by the actual amount moved.
+			float newc = [sv RB___dividerOrigin:actDivider];
+			DIM(point) += newc-divc;
+			divc = newc;
+			NSEnableScreenUpdates();
+			[pool release];
+		}
+		[sv RB___setDragging:NO];
+		[NSCursor pop];
+		actDivider = NSNotFound;
+		return;
+	}
+	if (canDragWindow&&[window isMovableByWindowBackground]&&![[self couplingSplitView] background]) {
+// If we get here, it's a textured (metal) window, the mouse has gone down on an non-opaque portion
+// of the subview, and our RBSplitView has a transparent background. RBSplitView returns NO to
+// mouseDownCanMoveWindow, but the window should move here - after all, the window background
+// is visible right here! So we fake it and move the window as intended. Mwahahaha!
+		where =  [window convertBaseToScreen:where];
+		NSPoint origin = [window frame].origin;
+// Now we loop handling mouse events until we get a mouse up event.
+		while ((theEvent = [NSApp nextEventMatchingMask:NSLeftMouseDownMask|NSLeftMouseDraggedMask|NSLeftMouseUpMask untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:YES])&&([theEvent type]!=NSLeftMouseUp)) {
+// Set up a local autorelease pool for the loop to prevent buildup of temporary objects.
+			NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+			NSPoint now = [window convertBaseToScreen:[theEvent locationInWindow]];
+			origin.x += now.x-where.x;
+			origin.y += now.y-where.y;
+// Move the window by the mouse displacement since the last event.
+			[window setFrameOrigin:origin];
+			where = now;
+			[pool release];
+		}
+	}
+}
+
+// These two methods encode and decode subviews.
+- (void)encodeWithCoder:(NSCoder*)coder {
+	NSRect frame;
+	BOOL coll = [self isCollapsed];
+	if (coll) {
+// We can't encode a collapsed subview as-is, so we correct the frame size first and add WAYOUT
+// to the origin to signal it was collapsed. 
+		NSRect newf = frame = [self frame];
+		newf.origin.x += WAYOUT;
+		[super setFrameOrigin:newf.origin];
+		newf.size = savedSize;
+		[super setFrameSize:newf.size];
+	}
+	[super encodeWithCoder:coder];
+	if (coll) {
+		[super setFrame:frame];
+	}
+	if ([coder allowsKeyedCoding]) {
+		[coder encodeObject:identifier forKey:@"identifier"];
+		[coder encodeInt:tag forKey:@"tag"];
+		[coder encodeFloat:minDimension forKey:@"minDimension"];
+		[coder encodeFloat:maxDimension forKey:@"maxDimension"];
+		[coder encodeDouble:fraction forKey:@"fraction"];
+		[coder encodeBool:canCollapse forKey:@"canCollapse"];
+	} else {
+		[coder encodeObject:identifier];
+		[coder encodeValueOfObjCType:@encode(typeof(tag)) at:&tag];
+		[coder encodeValueOfObjCType:@encode(typeof(minDimension)) at:&minDimension];
+		[coder encodeValueOfObjCType:@encode(typeof(maxDimension)) at:&maxDimension];
+		[coder encodeValueOfObjCType:@encode(typeof(fraction)) at:&fraction];
+		[coder encodeValueOfObjCType:@encode(typeof(canCollapse)) at:&canCollapse];
+	}
+}
+
+- (id)initWithCoder:(NSCoder*)coder {
+    if ((self = [super initWithCoder:coder])) {
+		fraction = 0.0;
+		canCollapse = NO;
+		notInLimits = NO;
+		minDimension = 1.0;
+		maxDimension = WAYOUT;
+		identifier = @"";
+		actDivider = NSNotFound;
+		canDragWindow = NO;
+		previous = [self frame];
+		savedSize = previous.size;
+		if (previous.origin.x>=WAYOUT) {
+// The subview was collapsed when encoded, so we correct the origin and collapse it.
+			BOOL ishor = [self splitViewIsHorizontal];
+			previous.origin.x -= WAYOUT;
+			DIM(previous.size) = 0.0;
+			[self setFrameOrigin:previous.origin];
+			[self setFrameSize:previous.size];
+		}
+		previous = NSZeroRect;
+		if ([coder allowsKeyedCoding]) {
+			[self setIdentifier:[coder decodeObjectForKey:@"identifier"]];
+			tag = [coder decodeIntForKey:@"tag"];
+			minDimension = [coder decodeFloatForKey:@"minDimension"];
+			maxDimension = [coder decodeFloatForKey:@"maxDimension"];
+			fraction = [coder decodeDoubleForKey:@"fraction"];
+			canCollapse = [coder decodeBoolForKey:@"canCollapse"];
+		} else {
+			[self setIdentifier:[coder decodeObject]];
+			[coder decodeValueOfObjCType:@encode(typeof(tag)) at:&tag];
+			[coder decodeValueOfObjCType:@encode(typeof(minDimension)) at:&minDimension];
+			[coder decodeValueOfObjCType:@encode(typeof(maxDimension)) at:&maxDimension];
+			[coder decodeValueOfObjCType:@encode(typeof(fraction)) at:&fraction];
+			[coder decodeValueOfObjCType:@encode(typeof(canCollapse)) at:&canCollapse];
+		}
+	}
+    return self;
+}
+
+@end
+
+@implementation RBSplitSubview (RB___SubviewAdditions)
+
+// This hides/shows the subview without calling adjustSubview.
+- (void)RB___setHidden:(BOOL)flag {
+	[super setHidden:flag];
+}
+
+// This internal method returns the current animationData. It will always return nil if
+// the receiver isn't the current owner and some other subview is already being animated.
+// Otherwise, if the parameter is YES, a new animation will be started (or the current
+// one will be restarted).
+- (animationData*)RB___animationData:(BOOL)start resize:(BOOL)resize {
+	if (currentAnimation&&(currentAnimation->owner!=self)) {
+// There already is an animation in progress on some other subview.
+		return nil;
+	}
+	if (start) {
+// We want to start (or restart) an animation.
+		RBSplitView* sv = [self splitView];
+		if (sv) {
+			float dim = [self dimension];
+// First assume the default time, then ask the delegate.
+			NSTimeInterval total = dim*(0.2/150.0);
+			id delegate = [sv delegate];
+			if ([delegate respondsToSelector:@selector(splitView:willAnimateSubview:withDimension:)]) {
+				total = [delegate splitView:sv willAnimateSubview:self withDimension:dim];
+			}
+// No use animating anything shorter than the frametime.
+			if (total>FRAMETIME) {
+				if (!currentAnimation) {
+					currentAnimation = (animationData*)malloc(sizeof(animationData));
+				}
+				if (currentAnimation) {
+					currentAnimation->owner = self;
+					currentAnimation->stepsDone = 0;
+					currentAnimation->elapsedTime = 0.0;
+					currentAnimation->dimension = dim;
+					currentAnimation->collapsing = ![self isCollapsed];
+					currentAnimation->totalTime = total;
+					currentAnimation->finishTime = [NSDate timeIntervalSinceReferenceDate]+total;
+					currentAnimation->resizing = resize;
+					[sv RB___setDragging:YES];
+				}
+			} else if (currentAnimation) {
+				free(currentAnimation);
+				currentAnimation = NULL;
+			}
+		}
+	}
+	return currentAnimation;
+}
+
+// This internal method steps the animation to the next frame.
+- (void)RB___stepAnimation {
+	NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
+	animationData* anim = [self RB___animationData:NO resize:NO];
+	if (anim) {
+		RBSplitView* sv = [self splitView];
+		NSTimeInterval remain = anim->finishTime-now;
+		NSRect frame = [self frame];
+		BOOL ishor = [sv isHorizontal];
+// Continuing animation only makes sense if we still have at least FRAMETIME available.
+		if (remain>=FRAMETIME) {
+			float dim = DIM(frame.size);
+			float avg = anim->elapsedTime;
+// We try to keep a record of how long it takes, on the average, to resize and adjust
+// one animation frame.
+			if (anim->stepsDone) {
+				avg /= anim->stepsDone;
+			}
+			NSTimeInterval delay = MIN(0.0,FRAMETIME-avg);
+// We adjust the new dimension proportionally to how much of the designated time has passed.
+			dim = floorf(anim->dimension*(remain-avg)/anim->totalTime);
+			if (dim>4.0) {
+				if (!anim->collapsing) {
+					dim = anim->dimension-dim;
+				} 
+				DIM(frame.size) = dim;
+				[self RB___setFrame:frame withFraction:0.0 notify:NO];
+				[sv adjustSubviews];
+				[self display];
+				anim->elapsedTime += [NSDate timeIntervalSinceReferenceDate]-now;
+				++anim->stepsDone;
+// Schedule a timer to do the next animation step.
+				[self performSelector:@selector(RB___stepAnimation) withObject:nil afterDelay:delay inModes:[NSArray arrayWithObjects:NSDefaultRunLoopMode,NSModalPanelRunLoopMode,
+					NSEventTrackingRunLoopMode,nil]];
+				return;
+			}
+		}
+// We're finished, either collapse or expand entirely now.
+		if (anim->collapsing) {
+			DIM(frame.size) = 0.0;
+			[self RB___finishCollapse:frame withFraction:anim->dimension/[sv RB___dimensionWithoutDividers]];
+		} else {
+			float savemin,savemax;
+			float dim = [self RB___setMinAndMaxTo:anim->dimension savingMin:&savemin andMax:&savemax];
+			DIM(frame.size) = dim;
+			[self RB___finishExpand:frame withFraction:0.0];
+			minDimension = savemin;
+			maxDimension = savemax;
+		}
+	}
+}
+
+// This internal method stops the animation, if the receiver is being animated. It will
+// return YES if the animation was stopped.
+- (BOOL)RB___stopAnimation {
+	if (currentAnimation&&(currentAnimation->owner==self)) {
+		[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(RB___stepAnimation) object:nil];
+		free(currentAnimation);
+		currentAnimation = NULL;
+		[[self splitView] RB___setDragging:NO];
+		return YES;
+	}
+	return NO;
+}
+
+// This internal method returns the actual visible dimension of the subview. Differs from -dimension in
+// that it returns 0.0 if the subview is collapsed.
+- (float)RB___visibleDimension {
+	BOOL ishor = [self splitViewIsHorizontal];
+	NSRect frame = [self frame];
+	return MAX(0.0,DIM(frame.size));
+}
+
+// This pair of internal methods is used only inside -[RBSplitView adjustSubviews] to copy subview data
+// from and to that method's internal cache.
+- (void)RB___copyIntoCache:(subviewCache*)cache {
+	cache->sub = self;
+	cache->rect = [self frame];
+	cache->size = [self RB___visibleDimension];
+	cache->fraction = fraction;
+	cache->constrain = NO;
+}
+
+- (void)RB___updateFromCache:(subviewCache*)cache withTotalDimension:(float)value {
+	float dim = [self RB___visibleDimension];
+	if (cache->size>=1.0) {
+// New state is not collapsed.
+		if (dim>=1.0) {
+// Old state was not collapsed, so we just change the frame.
+			[self RB___setFrame:cache->rect withFraction:cache->fraction notify:YES];
+		} else {
+// Old state was collapsed, so we expand it.
+			[self RB___finishExpand:cache->rect withFraction:cache->fraction];
+		}
+	} else {
+// New state is collapsed.
+		if (dim>=1.0) {
+// Old state was not collapsed, so we clear first responder and change the frame.
+			[self RB___clearResponder];
+			[self RB___finishCollapse:cache->rect withFraction:dim/value];
+		} else {
+// It was collapsed already, but the frame may have changed, so we set it.
+			[self RB___setFrame:cache->rect withFraction:cache->fraction notify:YES];
+		}
+	}
+}
+
+// This internal method sets minimum and maximum values to the same value, saves the old values,
+// and returns the new value (which will be limited to the old values).
+- (float)RB___setMinAndMaxTo:(float)value savingMin:(float*)oldmin andMax:(float*)oldmax {
+	*oldmin = [self minDimension];
+	*oldmax = [self maxDimension];
+	if (value<*oldmin) {
+		value = *oldmin;
+	}
+	if (value>*oldmax) {
+		value = *oldmax;
+	}
+	minDimension = maxDimension = value;
+	return value;
+}
+
+// This internal method tries to clear the first responder, if the current responder is a descendant of
+// the receiving subview. If so, it will set first responder to nil, redisplay the former responder and
+// return YES. Returns NO otherwise.
+- (BOOL)RB___clearResponder {
+	NSWindow* window = [self window];
+	if (window) {
+		NSView* responder = (NSView*)[window firstResponder];
+		if (responder&&[responder respondsToSelector:@selector(isDescendantOf:)]) {
+			if ([responder isDescendantOf:self]) {
+				if ([window makeFirstResponder:nil]) {
+					[responder display];
+					return YES;
+				}
+			}
+		}
+	}
+	return NO;
+}
+
+// This internal method collapses a subview.
+// It returns the negative of the size of the subview before collapsing, or 0.0 if it wasn't collapsed.
+- (float)RB___collapse {
+	float result = 0.0;
+	if (![self isCollapsed]) {
+		RBSplitView* sv = [self splitView];
+		if (sv&&[self canCollapse]) {
+			[self RB___clearResponder];
+			NSRect frame = [self frame];
+			BOOL ishor = [sv isHorizontal];
+			result = DIM(frame.size);
+// For collapsed views, fraction will contain the fraction of the dimension previously occupied
+			DIM(frame.size) = 0.0;
+			[self RB___finishCollapse:frame withFraction:result/[sv RB___dimensionWithoutDividers]];
+		}
+	}
+	return -result;
+}
+
+// This internal method finishes the collapse of a subview, stopping the animation if
+// there is one, and calling the delegate method if there is one.
+- (void)RB___finishCollapse:(NSRect)rect withFraction:(double)value {
+	RBSplitView* sv = [self splitView];
+	BOOL finish = [self RB___stopAnimation];
+	[self RB___setFrame:rect withFraction:value notify:YES];
+	[sv RB___setMustClearFractions];
+	if (finish) {
+		[self display];
+	}
+	id delegate = [sv delegate];
+	if ([delegate respondsToSelector:@selector(splitView:didCollapse:)]) {
+		[delegate splitView:sv didCollapse:self];
+	}
+}
+
+// This internal method expands a subview. setToMinimum will usually be YES during a divider drag.
+// It returns the size of the subview after expanding, or 0.0 if it wasn't expanded.
+- (float)RB___expandAndSetToMinimum:(BOOL)setToMinimum {
+	float result = 0.0;
+	RBSplitView* sv = [self splitView];
+	if (sv&&[self isCollapsed]) {
+		NSRect frame = [super frame];
+		double frac = fraction;
+		BOOL ishor = [sv isHorizontal];
+		if (setToMinimum) {
+			result = DIM(frame.size) = minDimension;
+		} else {
+			result = [sv RB___dimensionWithoutDividers]*frac;
+// We need to apply a compensation factor for proportional resizing in adjustSubviews.
+			float newdim = floorf((frac>=1.0)?result:result/(1.0-frac));
+			DIM(frame.size) = newdim;
+			result = floorf(result);
+		}
+		[self RB___finishExpand:frame withFraction:0.0];
+	}
+	return result;
+}
+
+// This internal method finishes the the expansion of a subview, stopping the animation if
+// there is one, and calling the delegate method if there is one.
+- (void)RB___finishExpand:(NSRect)rect withFraction:(double)value {
+	RBSplitView* sv = [self splitView];
+	BOOL finish = [self RB___stopAnimation];
+	[self RB___setFrame:rect withFraction:value notify:YES];
+	[sv RB___setMustClearFractions];
+	if (finish) {
+		[self display];
+	}
+	id delegate = [sv delegate];
+	if ([delegate respondsToSelector:@selector(splitView:didExpand:)]) {
+		[delegate splitView:sv didExpand:self];
+	}
+}
+
+// These internal methods set the subview's frame or size, and also store a fraction value
+// which is used to ensure repeatability when the whole split view is resized.
+- (void)RB___setFrame:(NSRect)rect withFraction:(double)value notify:(BOOL)notify {
+	RBSplitView* sv = [self splitView];
+	id delegate = nil;
+	if (notify) {
+		delegate = [sv delegate];
+// If the delegate method isn't implemented, we ignore the delegate altogether.
+		if ([delegate respondsToSelector:@selector(splitView:changedFrameOfSubview:from:to:)]) {
+// If the rects are equal, the delegate isn't called.
+			if (NSEqualRects(previous,rect)) {
+				delegate = nil;
+			}
+		} else {
+			delegate = nil;
+		}
+	}
+	[sv setMustAdjust];
+	[self setFrame:rect];
+	fraction = value;
+	[delegate splitView:sv changedFrameOfSubview:self from:previous to:rect];
+	previous = delegate?rect:NSZeroRect;
+}
+
+- (void)RB___setFrameSize:(NSSize)size withFraction:(double)value {
+	[[self splitView] setMustAdjust];
+	[self setFrameSize:size];
+	fraction = value;
+}
+
+// This internal method gets the fraction value.
+- (double)RB___fraction {
+	return fraction;
+}
+
+@end
+
diff --git a/src/MacVim/RBSplitView.h b/src/MacVim/RBSplitView.h
new file mode 100644
index 0000000..0c786c2
--- /dev/null
+++ b/src/MacVim/RBSplitView.h
@@ -0,0 +1,225 @@
+//
+//  RBSplitView.h version 1.1.4
+//  RBSplitView
+//
+//  Created by Rainer Brockerhoff on 24/09/2004.
+//  Copyright 2004-2006 Rainer Brockerhoff.
+//	Some Rights Reserved under the Creative Commons Attribution License, version 2.5, and/or the MIT License.
+//
+
+#import "RBSplitSubview.h"
+
+// These values are used to handle the various cursor types.
+typedef enum {
+	RBSVHorizontalCursor=0,		// appears over horizontal dividers
+	RBSVVerticalCursor,			// appears over vertical dividers
+	RBSV2WayCursor,				// appears over two-way thumbs
+	RBSVDragCursor,				// appears while dragging
+	RBSVCursorTypeCount
+} RBSVCursorType;
+
+@interface RBSplitView : RBSplitSubview {
+// Subclasses normally should use setter methods instead of changing instance variables by assignment.
+// Most getter methods simply return the corresponding instance variable, so with some care, subclasses
+// could reference them directly.
+	IBOutlet id delegate;		// The delegate (may be nil).
+	NSString* autosaveName;		// This name is used for storing subview proportions in user defaults.
+	NSColor* background;		// The color used to paint the view's background (may be nil).
+	NSImage* divider;			// The image used for the divider "dimple".
+	NSRect* dividers;			// A C array of NSRects, one for each divider.
+	float dividerThickness;		// Actual divider width; should be an integer and at least 1.0.
+	BOOL mustAdjust;			// Set internally if the subviews need to be adjusted.
+	BOOL mustClearFractions;	// Set internally if fractions should be cleared before adjusting.
+	BOOL isHorizontal;			// The divider's orientation; default is vertical.
+	BOOL canSaveState;			// Set internally to allow saving subview state.
+	BOOL isCoupled;				// If YES, take some parameters from the containing RBSplitView, if any.
+	BOOL isAdjusting;			// Set internally while the subviews are being adjusted.
+	BOOL isDragging;			// Set internally while in a drag loop.
+	BOOL isInScrollView;		// Set internally if directly contained in an NSScrollView.
+}
+
+// These class methods get and set the cursor used for each type.
+// Pass in nil to reset to the default cursor for that type.
++ (NSCursor*)cursor:(RBSVCursorType)type;
++ (void)setCursor:(RBSVCursorType)type toCursor:(NSCursor*)cursor;
+
+// This class method clears the saved state for a given autosave name from the defaults.
++ (void)removeStateUsingName:(NSString*)name;
+
+// This class method returns the actual key used to store autosave data in the defaults.
++ (NSString*)defaultsKeyForName:(NSString*)name isHorizontal:(BOOL)orientation;
+
+// Sets and gets the autosaveName; this will be the key used to store the subviews' proportions
+// in the user defaults. Default is @"", which doesn't save anything. Set flag to YES to set
+// unique names for nested subviews. You are responsible for avoiding duplicates.
+- (void)setAutosaveName:(NSString*)aString recursively:(BOOL)flag;
+- (NSString*)autosaveName;
+
+// Saves the current state of the subviews if there's a valid autosave name set. If the argument
+// is YES, it's then also called recursively for nested RBSplitViews. Returns YES if successful.
+- (BOOL)saveState:(BOOL)recurse;
+
+// Restores the saved state of the subviews if there's a valid autosave name set. If the argument
+// is YES, it's first called recursively for nested RBSplitViews. Returns YES if successful.
+// You need to call adjustSubviews after calling this.
+- (BOOL)restoreState:(BOOL)recurse;
+
+// Returns a string encoding the current state of all direct subviews. Does not check for nesting.
+- (NSString*)stringWithSavedState;
+
+// Readjusts all direct subviews according to the encoded string parameter. The number of subviews
+// must match. Returns YES if successful. Does not check for nesting.
+- (BOOL)setStateFromString:(NSString*)aString;
+
+// Returns an array with complete state information for the receiver and all subviews, taking
+// nesting into account. Don't store this array in a file, as its format might change in the
+// future; this is for taking a state snapshot and later restoring it with setStatesFromArray.
+- (NSArray*)arrayWithStates;
+
+// Restores the state of the receiver and all subviews. The array must have been produced by a
+// previous call to arrayWithStates. Returns YES if successful. This will fail if you have
+// added or removed subviews in the meantime!
+// You need to call adjustSubviews after calling this.
+- (BOOL)setStatesFromArray:(NSArray*)array;
+
+// This is the designated initializer for creating RBSplitViews programmatically.
+- (id)initWithFrame:(NSRect)frame;
+
+// This convenience initializer adds any number of subviews and adjusts them proportionally.
+- (id)initWithFrame:(NSRect)frame andSubviews:(unsigned)count;
+
+// Sets and gets the delegate. (Delegates aren't retained.) See further down for delegate methods.
+- (void)setDelegate:(id)anObject;
+- (id)delegate;
+
+// Returns a subview which has a certain identifier string, or nil if there's none
+- (RBSplitSubview*)subviewWithIdentifier:(NSString*)anIdentifier;
+
+// Returns the subview at a certain position. Returns nil if the position is invalid.
+- (RBSplitSubview*)subviewAtPosition:(unsigned)position;
+
+// Adds a subview at a certain position.
+- (void)addSubview:(NSView*)aView atPosition:(unsigned)position;
+
+// Sets and gets the divider thickness, which should be a positive integer or zero.
+// Setting the divider image also resets this automatically, so you would call this
+// only if you want the divider to be larger or smaller than the image. Zero means that
+// the image dimensions will be used.
+- (void)setDividerThickness:(float)thickness;
+- (float)dividerThickness;
+
+// Sets and gets the divider image. The default image can also be set in Interface Builder, so usually
+// there's no need to call this. Passing in nil means that the default divider thickness will be zero,
+// and no mouse events will be processed, so that the dividers can be moved only programmatically.
+- (void)setDivider:(NSImage*)image;
+- (NSImage*)divider;
+
+// Sets and gets the view background. The default is nil, meaning no background is
+// drawn and the view and its subviews are considered transparent.
+- (void)setBackground:(NSColor*)color;
+- (NSColor*)background;
+
+// Sets and gets the orientation. This uses the same convention as NSSplitView: vertical means the
+// dividers are vertical, but the subviews are in a horizontal row. Sort of counter-intuitive, yes.
+- (void)setVertical:(BOOL)flag;
+- (BOOL)isVertical;
+- (BOOL)isHorizontal;
+
+// Call this to force adjusting the subviews before display. Called automatically if anything
+// relevant is changed.
+- (void)setMustAdjust;
+
+// Returns YES if there's a pending adjustment.
+- (BOOL)mustAdjust;
+
+// Returns YES if we're in a dragging loop.
+- (BOOL)isDragging;
+
+// Returns YES if the view is directly contained in an NSScrollView.
+- (BOOL)isInScrollView;
+
+// Call this to recalculate all subview dimensions. Normally this is done automatically whenever
+// something relevant is changed, so you rarely will need to call this explicitly.
+- (void)adjustSubviews;
+
+// This method should be called only from within the splitView:wasResizedFrom:to: delegate method
+// to keep some specific subview the same size.
+- (void)adjustSubviewsExcepting:(RBSplitSubview*)excepting;
+
+// This method draws dividers. You should never call it directly but you can override it when
+// subclassing, if you need custom dividers.
+- (void)drawDivider:(NSImage*)anImage inRect:(NSRect)rect betweenView:(RBSplitSubview*)leading andView:(RBSplitSubview*)trailing;
+
+@end
+
+// The following methods are optionally implemented by the delegate.
+
+@interface NSObject(RBSplitViewDelegate)
+
+// The delegate can override a subview's ability to collapse by implementing this method.
+// Return YES to allow collapsing. If this is implemented, the subviews' built-in
+// 'collapsed' flags are ignored.
+- (BOOL)splitView:(RBSplitView*)sender canCollapse:(RBSplitSubview*)subview;
+
+// The delegate can alter the divider's appearance by implementing this method.
+// Before calling this, the divider is filled with the background, and afterwards
+// the divider image is drawn into the returned rect. If imageRect is empty, no
+// divider image will be drawn, because there are nested RBSplitViews. Return
+// NSZeroRect to suppress the divider image. Return imageRect to use the default
+// location for the image, or change its origin to place the image elsewhere.
+// You could also draw the divider yourself at this point and return NSZeroRect.
+- (NSRect)splitView:(RBSplitView*)sender willDrawDividerInRect:(NSRect)dividerRect betweenView:(RBSplitSubview*)leading andView:(RBSplitSubview*)trailing withProposedRect:(NSRect)imageRect;
+
+// These methods are called after a subview is completely collapsed or expanded. adjustSubviews may or may not
+// have been called, however.
+- (void)splitView:(RBSplitView*)sender didCollapse:(RBSplitSubview*)subview;
+- (void)splitView:(RBSplitView*)sender didExpand:(RBSplitSubview*)subview;
+
+// These methods are called just before and after adjusting subviews.
+- (void)willAdjustSubviews:(RBSplitView*)sender;
+- (void)didAdjustSubviews:(RBSplitView*)sender;
+
+// This method will be called after a RBSplitView is resized with setFrameSize: but before
+// adjustSubviews is called on it.
+- (void)splitView:(RBSplitView*)sender wasResizedFrom:(float)oldDimension to:(float)newDimension;
+
+// This method will be called when a divider is double-clicked and both leading and trailing
+// subviews can be collapsed. Return either of the parameters to collapse that subview, or nil
+// to collapse neither. If not implemented, the smaller subview will be collapsed.
+- (RBSplitSubview*)splitView:(RBSplitView*)sender collapseLeading:(RBSplitSubview*)leading orTrailing:(RBSplitSubview*)trailing;
+
+// This method will be called when a cursor rect is being set (inside resetCursorRects). The
+// proposed rect is passed in. Return the actual rect, or NSZeroRect to suppress cursor setting
+// for this divider. This won't be called for two-axis thumbs, however. The rects are in
+// sender's local coordinates.
+- (NSRect)splitView:(RBSplitView*)sender cursorRect:(NSRect)rect forDivider:(unsigned int)divider;
+
+// This method will be called whenever a mouse-down event is received in a divider. Return YES to have
+// the event handled by the split view, NO if you wish to ignore it or handle it in the delegate.
+- (BOOL)splitView:(RBSplitView*)sender shouldHandleEvent:(NSEvent*)theEvent inDivider:(unsigned int)divider betweenView:(RBSplitSubview*)leading andView:(RBSplitSubview*)trailing;
+
+// This method will be called just before a subview will be collapsed or expanded with animation.
+// Return the approximate time the animation should take, or 0.0 to disallow animation.
+// If not implemented, it will use the default of 0.2 seconds per 150 pixels.
+- (NSTimeInterval)splitView:(RBSplitView*)sender willAnimateSubview:(RBSplitSubview*)subview withDimension:(float)dimension;
+
+// This method will be called whenever a subview's frame is changed, usually from inside adjustSubviews' final loop.
+// You'd normally use this to move some auxiliary view to keep it aligned with the subview.
+- (void)splitView:(RBSplitView*)sender changedFrameOfSubview:(RBSplitSubview*)subview from:(NSRect)fromRect to:(NSRect)toRect;
+
+// This method is called whenever the event handlers want to check if some point within the RBSplitSubview
+// should act as an alternate drag view. Usually, the delegate will check the point (which is in sender's
+// local coordinates) against the frame of one or several auxiliary views, and return a valid divider number.
+// Returning NSNotFound means the point is not valid.
+- (unsigned int)splitView:(RBSplitView*)sender dividerForPoint:(NSPoint)point inSubview:(RBSplitSubview*)subview;
+
+// This method is called continuously while a divider is dragged, just before the leading subview is resized.
+// Return NO to resize the trailing view by the same amount, YES to resize the containing window by the same amount.
+- (BOOL)splitView:(RBSplitView*)sender shouldResizeWindowForDivider:(unsigned int)divider betweenView:(RBSplitSubview*)leading andView:(RBSplitSubview*)trailing willGrow:(BOOL)grow;
+
+// This method is called by each subview's drawRect: method, just after filling it with the background color but
+// before the contained subviews are drawn. Usually you would use this to draw a frame inside the subview.
+- (void)splitView:(RBSplitView*)sender willDrawSubview:(RBSplitSubview*)subview inRect:(NSRect)rect;
+
+@end
+
diff --git a/src/MacVim/RBSplitView.m b/src/MacVim/RBSplitView.m
new file mode 100644
index 0000000..057645a
--- /dev/null
+++ b/src/MacVim/RBSplitView.m
@@ -0,0 +1,1734 @@
+//
+//  RBSplitView.m version 1.1.4
+//  RBSplitView
+//
+//  Created by Rainer Brockerhoff on 24/09/2004.
+//  Copyright 2004-2006 Rainer Brockerhoff.
+//	Some Rights Reserved under the Creative Commons Attribution License, version 2.5, and/or the MIT License.
+//
+
+#import "RBSplitView.h"
+#import "RBSplitViewPrivateDefines.h"
+
+// Please don't remove this copyright notice!
+static const unsigned char RBSplitView_Copyright[] __attribute__ ((used)) =
+	"RBSplitView 1.1.4 Copyright(c)2004-2006 by Rainer Brockerhoff <rainer@brockerhoff.net>.";
+
+// This vector keeps currently used cursors. nil means the default cursor.
+static NSCursor* cursors[RBSVCursorTypeCount] = {nil};
+
+// Our own fMIN and fMAX
+static inline float fMIN(float a,float b) {
+	return a<b?a:b;
+}
+
+static inline float fMAX(float a,float b) {
+	return a>b?a:b;
+}
+
+@implementation RBSplitView
+
+// These class methods get and set the cursor used for each type.
+// Pass in nil to reset to the default cursor for that type.
++ (NSCursor*)cursor:(RBSVCursorType)type {
+	if ((type>=0)&&(type<RBSVCursorTypeCount)) {
+		NSCursor* result = cursors[type];
+		if (result) {
+			return result;
+		}
+		switch (type) {
+			case RBSVHorizontalCursor:
+				return [NSCursor resizeUpDownCursor];
+			case RBSVVerticalCursor:
+				return [NSCursor resizeLeftRightCursor];
+			case RBSV2WayCursor:
+				return [NSCursor openHandCursor];
+			case RBSVDragCursor:
+				return [NSCursor closedHandCursor];
+			default:
+				break;
+		}
+	}
+	return [NSCursor currentCursor];
+}
+
++ (void)setCursor:(RBSVCursorType)type toCursor:(NSCursor*)cursor {
+	if ((type>=0)&&(type<RBSVCursorTypeCount)) {
+		[cursors[type] release];
+		cursors[type] = [cursor retain];
+	}
+}
+
+// This class method clears the saved state(s) for a given autosave name from the defaults.
++ (void)removeStateUsingName:(NSString*)name {
+	if ([name length]) {
+		NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+		[defaults removeObjectForKey:[[self class] defaultsKeyForName:name isHorizontal:NO]];
+		[defaults removeObjectForKey:[[self class] defaultsKeyForName:name isHorizontal:YES]];
+	}
+}
+
+// This class method returns the actual key used to store autosave data in the defaults.
++ (NSString*)defaultsKeyForName:(NSString*)name isHorizontal:(BOOL)orientation {
+    return [NSString stringWithFormat:@"RBSplitView %@ %@",orientation?@"H":@"V",name];
+}
+
+// This pair of methods gets and sets the autosave name, which allows restoring the subview's
+// state from the user defaults.
+// We take care not to allow nil autosaveNames.
+- (NSString*)autosaveName {
+	return autosaveName;
+}
+
+// Sets the autosaveName; this should be a unique key to be used to store the subviews' proportions
+// in the user defaults. Default is @"", which doesn't save anything. Set flag to YES to set
+// unique names for nested subviews. You are responsible for avoiding duplicates; avoid using
+// the characters '[' and ']' in autosaveNames.
+- (void)setAutosaveName:(NSString*)aString recursively:(BOOL)flag {
+	BOOL clear;
+	if ((clear = ![aString length])) {
+		aString = @"";
+	}
+	[RBSplitView removeStateUsingName:autosaveName];
+	[autosaveName autorelease];
+	autosaveName = [aString retain];
+	if (flag) {
+		NSArray* subviews = [self subviews];
+		int subcount = [subviews count];
+		int i;
+		for (i=0;i<subcount;i++) {
+			RBSplitView* sv = [[subviews objectAtIndex:i] asSplitView];
+			if (sv) {
+				NSString* subst = clear?@"":[aString stringByAppendingFormat:@"[%d]",i];
+				[sv setAutosaveName:subst recursively:YES];
+			}
+		}
+	}
+}
+
+// Saves the current state of the subviews if there's a valid autosave name set. If the argument
+// is YES, it's then also called recursively for nested RBSplitViews. Returns YES if successful.
+// You must call restoreState explicity at least once before saveState will begin working.
+- (BOOL)saveState:(BOOL)recurse {
+// Saving the state is also disabled while dragging.
+	if (canSaveState&&![self isDragging]&&[autosaveName length]) {
+		[[NSUserDefaults standardUserDefaults] setObject:[self stringWithSavedState] forKey:[[self class] defaultsKeyForName:autosaveName isHorizontal:[self isHorizontal]]];
+		if (recurse) {
+			NSEnumerator* enumerator = [[self subviews] objectEnumerator];
+			RBSplitSubview* sub;
+			while ((sub = [enumerator nextObject])) {
+				[[sub asSplitView] saveState:YES];
+			}
+		}
+		return YES;
+	}
+	return NO;
+}
+
+// Restores the saved state of the subviews if there's a valid autosave name set. If the argument
+// is YES, it's also called recursively for nested RBSplitViews. Returns YES if successful.
+// It's good policy to call adjustSubviews immediately after calling restoreState.
+- (BOOL)restoreState:(BOOL)recurse {
+	BOOL result = NO;
+	if ([autosaveName length]) {
+		result = [self setStateFromString:[[NSUserDefaults standardUserDefaults] stringForKey:[[self class] defaultsKeyForName:autosaveName isHorizontal:[self isHorizontal]]]];
+		if (result&&recurse) {
+			NSEnumerator* enumerator = [[self subviews] objectEnumerator];
+			RBSplitSubview* sub;
+			while ((sub = [enumerator nextObject])) {
+				[[sub asSplitView] restoreState:YES];
+			}
+		}
+	}
+	canSaveState = YES;
+	return result;
+}
+
+// Returns an array with complete state information for the receiver and all subviews, taking
+// nesting into account. Don't store this array in a file, as its format might change in the
+// future; this is for taking a state snapshot and later restoring it with setStatesFromArray.
+- (NSArray*)arrayWithStates {
+	NSMutableArray* array = [NSMutableArray array];
+	[array addObject:[self stringWithSavedState]];
+	NSEnumerator* enumerator = [[self subviews] objectEnumerator];
+	RBSplitSubview* sub;
+	while ((sub = [enumerator nextObject])) {
+		RBSplitView* suv = [sub asSplitView];
+		if (suv) {
+			[array addObject:[suv arrayWithStates]];
+		} else {
+			[array addObject:[NSNull null]];
+		}
+	}
+	return array;
+}
+
+// Restores the state of the receiver and all subviews. The array must have been produced by a
+// previous call to arrayWithStates. Returns YES if successful. This will fail if you have
+// added or removed subviews in the meantime!
+// You need to call adjustSubviews after calling this.
+- (BOOL)setStatesFromArray:(NSArray*)array {
+	NSArray* subviews = [self subviews];
+	unsigned int count = [array count];
+	if (count==([subviews count]+1)) {
+		NSString* me = [array objectAtIndex:0];
+		if ([me isKindOfClass:[NSString class]]) {
+			if ([self setStateFromString:me]) {
+				unsigned int i;
+				for (i=1;i<count;i++) {
+					NSArray* item = [array objectAtIndex:i];
+					RBSplitView* suv = [[subviews objectAtIndex:i-1] asSplitView];
+					if ([item isKindOfClass:[NSArray class]]==(suv!=nil)) {
+						if (suv&&![suv setStatesFromArray:item]) {
+							return NO;
+						}
+					} else {
+						return NO;
+					}
+				}
+				return YES;
+			}
+		}
+	}
+	return NO;
+}
+
+// Returns a string encoding the current state of all direct subviews. Does not check for nesting.
+// The string contains the number of direct subviews, then the dimension for each subview (which will
+// be negative for collapsed subviews), all separated by blanks.
+- (NSString*)stringWithSavedState {
+	NSArray* subviews = [self subviews];
+	NSMutableString* result = [NSMutableString stringWithFormat:@"%d",[subviews count]];
+	NSEnumerator* enumerator = [subviews objectEnumerator];
+	RBSplitSubview* sub;
+	while ((sub = [enumerator nextObject])) {
+		double size = [sub dimension];
+		if ([sub isCollapsed]) {
+			size = -size;
+		} else {
+			size += +[sub RB___fraction];
+		}
+		[result appendFormat:[sub isHidden]?@" %gH":@" %g",size];
+	}
+	return result;
+}
+
+// Readjusts all direct subviews according to the encoded string parameter.
+// The number of subviews must match. Returns YES if successful. Does not check for nesting.
+- (BOOL)setStateFromString:(NSString*)aString {
+	if ([aString length]) {
+		NSArray* parts = [aString componentsSeparatedByString:@" "];
+		NSArray* subviews = [self subviews];
+		int subcount = [subviews count];
+		int k = [parts count];
+		if ((k-->1)&&([[parts objectAtIndex:0] intValue]==subcount)&&(k==subcount)) {
+			int i;
+			NSRect frame = [self frame];
+			BOOL ishor = [self isHorizontal];
+			for (i=0;i<subcount;i++) {
+				NSString* part = [parts objectAtIndex:i+1];
+				BOOL hidden = [part hasSuffix:@"H"];
+				double size = [part doubleValue];
+				BOOL negative = size<=0.0;
+				if (negative) {
+					size = -size;
+				}
+				double fract = size;
+				size = floorf(size);
+				fract -= size;
+				DIM(frame.size) = size;
+				RBSplitSubview* sub = [subviews objectAtIndex:i];
+				[sub RB___setFrame:frame withFraction:fract notify:NO];
+				if (negative) {
+					[sub RB___collapse];
+				}
+				[sub RB___setHidden:hidden];
+			}
+			[self setMustAdjust];
+			return YES;
+		}
+	}
+	return NO;
+}
+
+// This is the designated initializer for creating RBSplitViews programmatically. You can set the
+// divider image and other parameters afterwards.
+- (id)initWithFrame:(NSRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+ 		dividers = NULL;
+		isCoupled = YES;
+		isDragging = NO;
+		isInScrollView = NO;
+		canSaveState = NO;
+		[self setVertical:YES];
+		[self setDivider:nil];
+		[self setAutosaveName:nil recursively:NO];
+		[self setBackground:nil];
+	}
+	return self;
+}
+
+// This convenience initializer adds any number of subviews and adjusts them proportionally.
+- (id)initWithFrame:(NSRect)frame andSubviews:(unsigned)count {
+	self = [self initWithFrame:frame];
+	if (self) {
+		while (count-->0) {
+			[self addSubview:[[[RBSplitSubview alloc] initWithFrame:frame] autorelease]];
+		}
+		[self setMustAdjust];
+	}
+	return self;
+}
+
+// Frees retained objects when going away.
+- (void)dealloc {
+	if (dividers) {
+		free(dividers);
+	}
+	[autosaveName release];
+	[divider release];
+	[background release];
+	[super dealloc];
+}
+
+// Sets and gets the coupling between the view and its containing RBSplitView (if any). Coupled
+// RBSplitViews take some parameters, such as divider images, from the containing view. The default
+// is for nested RBSplitViews is YES; however, isCoupled returns NO if we're not nested.
+- (void)setCoupled:(BOOL)flag {
+	if (flag!=isCoupled) {
+		isCoupled = flag;
+// If we've just been uncoupled and there's no divider image, we copy it from the containing view. 
+		if (!isCoupled&&!divider) {
+			[self setDivider:[[self splitView] divider]];
+		}
+		[self setMustAdjust];
+	}
+}
+
+- (BOOL)isCoupled {
+	return isCoupled&&([super splitView]!=nil);
+}
+
+// This returns the containing splitview if they are coupled. It's guaranteed to return a RBSplitView or nil.
+- (RBSplitView*)couplingSplitView {
+	return isCoupled?[super couplingSplitView]:nil;
+}
+
+// This returns self.
+- (RBSplitView*)asSplitView {
+	return self;
+}
+
+// This return self if we're really coupled to the owning splitview.
+- (RBSplitView*)coupledSplitView {
+	return [self isCoupled]?self:nil;
+}
+
+// We always return NO, but do special handling in RBSplitSubview's mouseDown: method.
+- (BOOL)mouseDownCanMoveWindow {
+	return NO;
+}
+
+// RBSplitViews must be flipped to work properly for horizontal dividers. As the subviews are never
+// flipped, this won't make your life harder.
+- (BOOL)isFlipped {
+	return YES;
+}
+
+// Call this method to make sure that the subviews and divider rectangles are recalculated
+// properly before display.
+- (void)setMustAdjust {
+	mustAdjust = YES;
+	[self setNeedsDisplay:YES];
+}
+
+// Returns YES if there's a pending adjustment.
+- (BOOL)mustAdjust {
+	return mustAdjust;
+}
+
+// Returns YES if we're in a dragging loop.
+- (BOOL)isDragging {
+	return isDragging;
+}
+
+// Returns YES if the view is directly contained in an NSScrollView.
+- (BOOL)isInScrollView {
+	return isInScrollView;
+}
+
+// This pair of methods allows you to move the dividers for background windows while holding down
+// the command key, without bringing the window to the foreground.
+- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent {
+	return ([theEvent modifierFlags]&NSCommandKeyMask)==0;
+}
+
+- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent*)theEvent {
+	return ([theEvent modifierFlags]&NSCommandKeyMask)!=0;
+}
+
+// These 3 methods handle view background colors and opacity. The default is the window background.
+// Pass nil or a completely transparent color to setBackground to use transparency. If you set any
+// other background color, it will completely fill the RBSplitView (including subviews and dividers).
+// The view will be considered opaque only if its alpha is equal to 1.0.
+// For a nested, coupled RBSplitView, background and opacity are copied from the containing RBSplitView,
+// and setting the background has no effect.
+- (NSColor*)background {
+	RBSplitView* sv = [self couplingSplitView];
+	return sv?[sv background]:background;
+}
+
+- (void)setBackground:(NSColor*)color {
+	if (![self couplingSplitView]) {
+		[background autorelease];
+		background = color?([color alphaComponent]>0.0?[color retain]:nil):nil;
+		[self setNeedsDisplay:YES];
+	}
+}
+
+- (BOOL)isOpaque {
+	RBSplitView* sv = [self couplingSplitView];
+	return sv?[sv isOpaque]:(background&&([background alphaComponent]>=1.0));
+}
+
+// This will make debugging a little easier by appending the state string to the
+// default description.
+- (NSString*)description {
+	return [NSString stringWithFormat:@"%@ {%@}",[super description],[self stringWithSavedState]];
+}
+
+// The following 3 methods handle divider orientation. The actual stored trait is horizontality,
+// but verticality is used for setting to conform to the NSSplitView convention.
+// For a nested RBSplitView, orientation is perpendicular to the containing RBSplitView, and
+// setting it has no effect. This parameter is not affected by coupling.
+// After changing the orientation you may want to restore the state with restoreState:.
+- (BOOL)isHorizontal {
+	RBSplitView* sv = [self splitView];
+	return sv?[sv isVertical]:isHorizontal;
+}
+
+- (BOOL)isVertical {
+	return 1-[self isHorizontal];
+}
+
+- (void)setVertical:(BOOL)flag {
+	if (![self splitView]&&(isHorizontal!=!flag)) {
+		BOOL ishor = isHorizontal = !flag;
+		NSSize size = divider?[divider size]:NSZeroSize;
+		[self setDividerThickness:DIM(size)];
+		[self setMustAdjust];
+	}
+}
+
+// Returns the subview which a given identifier.
+- (RBSplitSubview*)subviewWithIdentifier:(NSString*)anIdentifier {
+	NSEnumerator* enumerator = [[self subviews] objectEnumerator];
+	RBSplitSubview* subview;
+	while ((subview = [enumerator nextObject])) {
+		if ([anIdentifier isEqualToString:[subview identifier]]) {
+			return subview;
+		}
+	}
+	return nil;
+}
+
+// Returns the subview at a given position
+- (RBSplitSubview*)subviewAtPosition:(unsigned)position {
+	NSArray* subviews = [super subviews];
+	unsigned int subcount = [subviews count];
+	if (position<subcount) {
+		return [subviews objectAtIndex:position];
+	}
+	return nil;
+}
+
+// This pair of methods gets and sets the delegate object. Delegates aren't retained.
+- (id)delegate {
+	return delegate;
+}
+
+- (void)setDelegate:(id)anObject {
+	delegate = anObject;
+}
+
+// This pair of methods gets and sets the divider image. Setting the image automatically adjusts the
+// divider thickness. A nil image means a 0-pixel wide divider, unless you set a thickness explicitly.
+// For a nested RBSplitView, the divider is copied from the containing RBSplitView, and
+// setting it has no effect. The returned image is always flipped.
+- (NSImage*)divider {
+	RBSplitView* sv = [self couplingSplitView];
+	return sv?[sv divider]:divider;
+}
+
+- (void)setDivider:(NSImage*)image {
+	if (![self couplingSplitView]) {
+		[divider autorelease];
+		if ([image isFlipped]) {
+// If the image is flipped, we just retain it.
+			divider = [image retain];
+		} else {
+// if the image isn't flipped, we copy the image instead of retaining it, and flip it.
+			divider = [image copy];
+			[divider setFlipped:YES];
+		}
+// We set the thickness to 0.0 so the image dimension will prevail.
+		[self setDividerThickness:0.0];
+		[self setMustAdjust];
+	}
+}
+
+// This pair of methods gets and sets the divider thickness. It should be an integer value and at least
+// 0.0, so we make sure. Set it to 0.0 to make the image dimensions prevail.
+- (float)dividerThickness {
+	if (dividerThickness>0.0) {
+		return dividerThickness;
+	}
+	NSImage* divdr = [self divider];
+	if (divdr) {
+		NSSize size = [divdr size];
+		BOOL ishor = [self isHorizontal];
+		return DIM(size);
+	}
+	return 0.0;
+}
+
+- (void)setDividerThickness:(float)thickness {
+	float t = fMAX(0.0,floorf(thickness));
+	if ((int)dividerThickness!=(int)t) {
+		dividerThickness = t;
+		[self setMustAdjust];
+	}
+}
+
+// These three methods add subviews. If aView isn't a RBSplitSubview, one is automatically inserted above
+// it, and aView's frame and resizing mask is set to occupy the entire RBSplitSubview.
+- (void)addSubview:(NSView*)aView {
+	if ([aView isKindOfClass:[RBSplitSubview class]]) {
+		[super addSubview:aView];
+	} else {
+		[aView setFrameOrigin:NSZeroPoint];
+		RBSplitSubview* sub = [[[RBSplitSubview alloc] initWithFrame:[aView frame]] autorelease];
+		[aView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
+		[sub addSubview:aView];
+		[super addSubview:sub];
+	}
+	[self setMustAdjust];
+}
+
+- (void)addSubview:(NSView*)aView positioned:(NSWindowOrderingMode)place relativeTo:(NSView*)otherView {
+	if ([aView isKindOfClass:[RBSplitSubview class]]) {
+		[super addSubview:aView positioned:place relativeTo:otherView];
+	} else {
+		[aView setFrameOrigin:NSZeroPoint];
+		RBSplitSubview* sub = [[[RBSplitSubview alloc] initWithFrame:[aView frame]] autorelease];
+		[aView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
+		[sub addSubview:aView];
+		[super addSubview:sub positioned:place relativeTo:otherView];
+		[aView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
+	}
+	[self setMustAdjust];
+}
+
+- (void)addSubview:(NSView*)aView atPosition:(unsigned)position {
+	RBSplitSubview* suv = [self subviewAtPosition:position];
+	if (suv) {
+		[self addSubview:aView positioned:NSWindowBelow relativeTo:suv];
+	} else {
+		[self addSubview:aView];
+	}
+}
+
+// This keeps the isInScrollView flag up-to-date.
+- (void)viewDidMoveToSuperview {
+	[super viewDidMoveToSuperview];
+	NSScrollView* scrollv = [self enclosingScrollView];
+	isInScrollView = scrollv?[scrollv documentView]==self:NO;
+}
+
+// This makes sure the subviews are adjusted after a subview is removed.
+- (void)willRemoveSubview:(NSView*)subview {
+	if ([subview respondsToSelector:@selector(RB___stopAnimation)]) {
+		[(RBSplitSubview*)subview RB___stopAnimation];
+	}
+	[super willRemoveSubview:subview];
+	[self setMustAdjust];
+}
+
+// RBSplitViews never resize their subviews automatically.
+- (BOOL)autoresizesSubviews {
+	return NO;
+}
+
+// This adjusts the subviews when the size is set. setFrame: calls this, so all is well. It calls
+// the delegate if implemented.
+- (void)setFrameSize:(NSSize)size {
+	NSSize oldsize = [self frame].size;
+	[super setFrameSize:size];
+	[self setMustAdjust];
+	if ([delegate respondsToSelector:@selector(splitView:wasResizedFrom:to:)]) {
+		BOOL ishor = [self isHorizontal];
+		float olddim = DIM(oldsize);
+		float newdim = DIM(size);
+// The delegate is not called if the dimension hasn't changed.
+		if (((int)newdim!=(int)olddim)) {
+			[delegate splitView:self wasResizedFrom:olddim to:newdim];
+		}
+	}
+// We adjust the subviews only if the delegate didn't.
+	if (mustAdjust&&!isAdjusting) {
+		[self adjustSubviews];
+	}
+}
+
+// This method handles dragging and double-clicking dividers with the mouse. While dragging, the
+// "closed hand" cursor is shown. Double clicks are handled separately. Nothing will happen if
+// no divider image is set.
+- (void)mouseDown:(NSEvent*)theEvent {
+	if (!dividers) {
+		return;
+	}
+	NSArray* subviews = [self RB___subviews];
+	int subcount = [subviews count];
+	if (subcount<2) {
+		return;
+	}
+// If the mousedown was in an alternate dragview, or if there's no divider image, handle it in RBSplitSubview.
+	if ((actDivider<NSNotFound)||![self divider]) {
+		[super mouseDown:theEvent];
+		return;
+	}
+	NSPoint where = [self convertPoint:[theEvent locationInWindow] fromView:nil];
+	BOOL ishor = [self isHorizontal];
+	int i;
+	--subcount;
+// Loop over the divider rectangles.
+	for (i=0;i<subcount;i++) {
+		NSRect* divdr = &dividers[i];
+		if ([self mouse:where inRect:*divdr]) {
+// leading points at the subview immediately leading the divider being tracked.
+			RBSplitView* leading = [subviews objectAtIndex:i];
+// trailing points at the subview immediately trailing the divider being tracked.
+			RBSplitView* trailing = [subviews objectAtIndex:i+1];
+			if ([delegate respondsToSelector:@selector(splitView:shouldHandleEvent:inDivider:betweenView:andView:)]) {
+				if (![delegate splitView:self shouldHandleEvent:theEvent inDivider:i betweenView:leading andView:trailing]) {
+					return;
+				}
+			}
+// If it's a double click, try to expand or collapse one of the neighboring subviews.
+			if ([theEvent clickCount]>1) {
+// If both are collapsed, we do nothing. If one of them is collapsed, we try to expand it.
+				if ([trailing isCollapsed]) {
+					if (![leading isCollapsed]) {
+						[self RB___tryToExpandTrailing:trailing leading:leading delta:-[trailing dimension]];
+					}
+				} else {
+					if ([leading isCollapsed]) {
+						[self RB___tryToExpandLeading:leading divider:i trailing:trailing delta:[leading dimension]];
+					} else {
+// If neither are collapsed, we check if both are collapsible.
+						BOOL lcan = [leading canCollapse];
+						BOOL tcan = [trailing canCollapse];
+						float ldim = [leading dimension];
+						if (lcan&&tcan) {
+// If both are collapsible, we try asking the delegate.
+							if ([delegate respondsToSelector:@selector(splitView:collapseLeading:orTrailing:)]) {
+								RBSplitSubview* sub = [delegate splitView:self collapseLeading:leading orTrailing:trailing];
+// If the delegate returns nil, neither view will collapse.
+								lcan = sub==leading;
+								tcan = sub==trailing;
+							} else {
+// Otherwise we try collapsing the smaller one. If they're equal, the trailing one will be collapsed.
+								lcan = ldim<[trailing dimension];
+							}
+						}
+// At this point, we'll try to collapse the leading subview.
+						if (lcan) {
+							[self RB___tryToShortenLeading:leading divider:i trailing:trailing delta:-ldim always:NO];
+						}
+// If the leading subview didn't collapse for some reason, we try to collapse the trailing one.
+						if (!mustAdjust&&tcan) {
+							[self RB___tryToShortenTrailing:trailing divider:i leading:leading delta:[trailing dimension] always:NO];
+						}
+					}
+				}
+// If the subviews have changed, clear the fractions, adjust and redisplay
+				if (mustAdjust) {
+					[self RB___setMustClearFractions];
+					RBSplitView* sv = [self splitView];
+					[sv?sv:self adjustSubviews];
+					[super display];
+				}
+			} else {
+// Single click; record the offsets within the divider rectangle and check for nesting.
+				float divt = [self dividerThickness];
+				float offset = DIM(where)-DIM(divdr->origin);
+// Check if the leading subview is nested and if yes, if one of its two-axis thumbs was hit.
+				int ldivdr = NSNotFound;
+				float loffset = 0.0;
+				NSPoint lwhere = where;
+				NSRect lrect = NSZeroRect;
+				if ((leading = [leading coupledSplitView])) {
+					ldivdr = [leading RB___dividerHitBy:lwhere relativeToView:self thickness:divt];
+					if (ldivdr!=NSNotFound) {
+						lrect = [leading RB___dividerRect:ldivdr relativeToView:self];
+						loffset = OTHER(lwhere)-OTHER(lrect.origin);
+					}
+				}
+// Check if the trailing subview is nested and if yes, if one of its two-axis thumbs was hit.
+				int tdivdr = NSNotFound;
+				float toffset = 0.0;
+				NSPoint twhere = where;
+				NSRect trect = NSZeroRect;
+				if ((trailing = [trailing coupledSplitView])) {
+					tdivdr = [trailing RB___dividerHitBy:twhere relativeToView:self thickness:divt];
+					if (tdivdr!=NSNotFound) {
+						trect = [trailing RB___dividerRect:tdivdr relativeToView:self];
+						toffset = OTHER(twhere)-OTHER(trect.origin);
+					}
+				}
+// Now we loop handling mouse events until we get a mouse up event, while showing the drag cursor.
+				[[RBSplitView cursor:RBSVDragCursor] push];
+				[self RB___setDragging:YES];
+				while ((theEvent = [NSApp nextEventMatchingMask:NSLeftMouseDownMask|NSLeftMouseDraggedMask|NSLeftMouseUpMask untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:YES])&&([theEvent type]!=NSLeftMouseUp)) {
+// Set up a local autorelease pool for the loop to prevent buildup of temporary objects.
+					NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+					NSDisableScreenUpdates();
+// Track the mouse along the main coordinate. 
+					[self RB___trackMouseEvent:theEvent from:where withBase:NSZeroPoint inDivider:i];
+					if (ldivdr!=NSNotFound) {
+// Track any two-axis thumbs for the leading nested RBSplitView.
+						[leading RB___trackMouseEvent:theEvent from:[self convertPoint:lwhere toView:leading] withBase:NSZeroPoint inDivider:ldivdr];
+					}
+					if (tdivdr!=NSNotFound) {
+// Track any two-axis thumbs for the trailing nested RBSplitView.
+						[trailing RB___trackMouseEvent:theEvent from:[self convertPoint:twhere toView:trailing] withBase:NSZeroPoint inDivider:tdivdr];
+					}
+					if (mustAdjust||[leading mustAdjust]||[trailing mustAdjust]) {
+// The mouse was dragged and the subviews changed, so we must redisplay, as
+// several divider rectangles may have changed.
+						RBSplitView* sv = [self splitView];
+						[sv?sv:self adjustSubviews];
+						[super display];
+						divdr = &dividers[i];
+// Adjust to the new cursor coordinates.
+						DIM(where) = DIM(divdr->origin)+offset;
+						if ((ldivdr!=NSNotFound)&&![leading isCollapsed]) {
+// Adjust for the leading nested RBSplitView's thumbs while it's not collapsed.
+							lrect = [leading RB___dividerRect:ldivdr relativeToView:self];
+							OTHER(lwhere) = OTHER(lrect.origin)+loffset;
+						}
+						if ((tdivdr!=NSNotFound)&&![trailing isCollapsed]) {
+// Adjust for the trailing nested RBSplitView's thumbs while it's not collapsed.
+							trect = [trailing RB___dividerRect:tdivdr relativeToView:self];
+							OTHER(twhere) = OTHER(trect.origin)+toffset;
+						}
+					}
+					NSEnableScreenUpdates();
+					[pool release];
+				}
+				[self RB___setDragging:NO];
+// Redisplay the previous cursor.
+				[NSCursor pop];
+			}
+		}
+	}
+}
+
+// This will be called before the view will be redisplayed, so we adjust subviews if necessary.
+- (BOOL)needsDisplay {
+	if (mustAdjust&&!isAdjusting) {
+		[self adjustSubviews];
+		return YES;
+	}
+	return [super needsDisplay];
+}
+
+// We implement awakeFromNib to restore the state. This works if an autosaveName is set in the nib.
+- (void)awakeFromNib {
+	if ([RBSplitSubview instancesRespondToSelector:@selector(awakeFromNib)]) {
+		[super awakeFromNib];
+	}
+	if (![self splitView]) {
+		[self restoreState:YES];
+	}
+}
+
+// We check if subviews must be adjusted before redisplaying programmatically.
+- (void)display {
+	if (mustAdjust&&!isAdjusting) {
+		[self adjustSubviews];
+	}
+	[super display];
+}
+
+// This method draws the divider rectangles and then the two-axis thumbs if there are any.
+- (void)drawRect:(NSRect)rect {
+	[super drawRect:rect];
+	if (!dividers) {
+		return;
+	}
+	NSArray* subviews = [self RB___subviews];
+	int subcount = [subviews count];
+// Return if there are no dividers to draw.
+	if (subcount<2) {
+		return;
+	}
+	--subcount;
+	int i;
+// Cache the divider image.
+	NSImage* divdr = [self divider];
+	float divt = [self dividerThickness];
+// Loop over the divider rectangles.
+	for (i=0;i<subcount;i++) {
+// Check if we need to draw this particular divider.
+		if ([self needsToDrawRect:dividers[i]]) {
+			RBSplitView* leading = [subviews objectAtIndex:i];
+			RBSplitView* trailing = [subviews objectAtIndex:i+1];
+			BOOL lexp = divdr?![leading isCollapsed]:NO;
+			BOOL texp = divdr?![trailing isCollapsed]:NO;
+// We don't draw the divider image if either of the neighboring subviews is a non-collapsed
+// nested split view.
+			BOOL nodiv = (lexp&&[leading coupledSplitView])||(texp&&[trailing coupledSplitView]);
+			[self drawDivider:nodiv?nil:divdr inRect:dividers[i] betweenView:leading andView:trailing];
+			if (divdr) {
+// Draw the corresponding two-axis thumbs if the leading view is a nested RBSplitView.
+				if ((leading = [leading coupledSplitView])&&lexp) {
+					[leading RB___drawDividersIn:self forDividerRect:dividers[i] thickness:divt];
+				}
+// Draw the corresponding two-axis thumbs if the trailing view is a nested RBSplitView.
+				if ((trailing = [trailing coupledSplitView])&&texp) {
+					[trailing RB___drawDividersIn:self forDividerRect:dividers[i] thickness:divt];
+				}
+			}
+		}
+	}
+}
+
+// This method draws dividers. You should never call it directly but you can override it when
+// subclassing, if you need custom dividers. It draws the divider image centered in the divider rectangle.
+// If we're drawing a two-axis thumb leading and trailing will be nil, and the rectangle
+// will be the thumb rectangle.
+// If there are nested split views this will be called once to draw the main divider rect,
+// and again for every thumb.
+- (void)drawDivider:(NSImage*)anImage inRect:(NSRect)rect betweenView:(RBSplitSubview*)leading andView:(RBSplitSubview*)trailing {
+// Fill the view with the background color (if there's any). Don't draw the background again for
+// thumbs.
+	if (leading||trailing) {
+		NSColor* bg = [self background];
+		if (bg) {
+			[bg set];
+			NSRectFillUsingOperation(rect,NSCompositeSourceOver);
+		}
+	}
+// Center the image, if there is one.
+	NSRect imrect = NSZeroRect;
+	NSRect dorect = NSZeroRect;
+	if (anImage) {
+		imrect.size = dorect.size = [anImage size];
+		dorect.origin = NSMakePoint(floorf(rect.origin.x+(rect.size.width-dorect.size.width)/2),
+									floorf(rect.origin.y+(rect.size.height-dorect.size.height)/2));
+	}
+// Ask the delegate for the final rect where the image should be drawn.
+	if ([delegate respondsToSelector:@selector(splitView:willDrawDividerInRect:betweenView:andView:withProposedRect:)]) {
+		dorect = [delegate splitView:self willDrawDividerInRect:rect betweenView:leading andView:trailing withProposedRect:dorect];
+	}
+// Draw the image if the delegate returned a non-empty rect.
+	if (!NSIsEmptyRect(dorect)) {
+		[anImage drawInRect:dorect fromRect:imrect operation:NSCompositeSourceOver fraction:1.0];
+	}
+}
+
+// This method should be called only from within the splitView:wasResizedFrom:to: delegate method
+// to keep some specific subview the same size.
+- (void)adjustSubviewsExcepting:(RBSplitSubview*)excepting {
+	[self RB___adjustSubviewsExcepting:[excepting isCollapsed]?nil:excepting];
+}
+
+// This method adjusts subviews and divider rectangles.
+- (void)adjustSubviews {
+	[self RB___adjustSubviewsExcepting:nil];
+}
+
+// This resets the appropriate cursors for each divider according to the orientation.
+// No cursors are shown if there is no divider image.
+- (void)resetCursorRects {
+	if (!dividers) {
+		return;
+	}
+	id del = [delegate respondsToSelector:@selector(splitView:cursorRect:forDivider:)]?delegate:nil;
+	NSArray* subviews = [self RB___subviews];
+	int divcount = [subviews count]-1;
+	if ((divcount<1)||![self divider]) {
+		[del splitView:self cursorRect:NSZeroRect forDivider:0];
+		return;
+	}
+	int i;
+	NSCursor* cursor = [RBSplitView cursor:[self isVertical]?RBSVVerticalCursor:RBSVHorizontalCursor];
+	float divt = [self dividerThickness];
+	for (i=0;i<divcount;i++) {
+		RBSplitView* sub = [[subviews objectAtIndex:i] coupledSplitView];
+// If the leading subview is a nested RBSplitView, add the thumb rectangles first.
+		if (sub) {
+			[sub  RB___addCursorRectsTo:self forDividerRect:dividers[i] thickness:divt];
+		}
+		sub = [[subviews objectAtIndex:i+1] coupledSplitView];
+// If the trailing subview is a nested RBSplitView, add the thumb rectangles first.
+		if (sub) {
+			[sub  RB___addCursorRectsTo:self forDividerRect:dividers[i] thickness:divt];
+		}
+// Now add thedivider rectangle.
+		NSRect divrect = dividers[i];
+		if (del) {
+			divrect = [del splitView:self cursorRect:divrect forDivider:i];
+		}
+		if (!NSIsEmptyRect(divrect)) {
+			[self addCursorRect:divrect cursor:cursor];
+		}
+	}
+}
+
+// These two methods encode and decode RBSplitViews. One peculiarity is that we encode the divider image's
+// bitmap representation as data; this makes the nib files larger, but the user can just paste any image
+// into the RBSplitView inspector - or use the default divider image - without having to include it into the
+// project, too.
+- (void)encodeWithCoder:(NSCoder *)coder {
+	[super encodeWithCoder:coder];
+	if ([coder allowsKeyedCoding]) {
+        [coder encodeConditionalObject:delegate forKey:@"delegate"];
+		[coder encodeObject:autosaveName forKey:@"autosaveName"];
+		[coder encodeObject:[divider TIFFRepresentation] forKey:@"divider"];
+		[coder encodeObject:background forKey:@"background"];
+		[coder encodeFloat:dividerThickness forKey:@"dividerThickness"];
+		[coder encodeBool:isHorizontal forKey:@"isHorizontal"];
+		[coder encodeBool:isCoupled forKey:@"isCoupled"];
+	} else {
+		[coder encodeConditionalObject:delegate];
+		[coder encodeObject:autosaveName];
+		[coder encodeObject:[divider TIFFRepresentation]];
+		[coder encodeObject:background];
+		[coder encodeValueOfObjCType:@encode(typeof(dividerThickness)) at:&dividerThickness];
+		[coder encodeValueOfObjCType:@encode(typeof(isHorizontal)) at:&isHorizontal];
+		[coder encodeValueOfObjCType:@encode(typeof(isCoupled)) at:&isCoupled];
+	}
+}
+
+- (id)initWithCoder:(NSCoder *)coder {
+    if ((self = [super initWithCoder:coder])) {
+		NSData* data = nil;
+		float divt = 0.0;
+		isCoupled = YES;
+		isDragging = NO;
+		isInScrollView = NO;
+		canSaveState = NO;
+		if ([coder allowsKeyedCoding]) {
+			isCoupled = [coder decodeBoolForKey:@"isCoupled"];
+			[self setDelegate:[coder decodeObjectForKey:@"delegate"]];
+			[self setAutosaveName:[coder decodeObjectForKey:@"autosaveName"] recursively:NO];
+			data = [coder decodeObjectForKey:@"divider"];
+			[self setBackground:[coder decodeObjectForKey:@"background"]];
+			divt = [coder decodeFloatForKey:@"dividerThickness"];
+			isHorizontal = [coder decodeBoolForKey:@"isHorizontal"];
+		} else {
+			[self setDelegate:[coder decodeObject]];
+			[self setAutosaveName:[coder decodeObject] recursively:NO];
+			data = [coder decodeObject];
+			[self setBackground:[coder decodeObject]];
+			[coder decodeValueOfObjCType:@encode(typeof(divt)) at:&divt];
+			[coder decodeValueOfObjCType:@encode(typeof(isHorizontal)) at:&isHorizontal];
+			[coder decodeValueOfObjCType:@encode(typeof(isCoupled)) at:&isCoupled];
+		}
+		dividers = NULL;
+		if (data) {
+			NSBitmapImageRep* rep = [NSBitmapImageRep imageRepWithData:data];
+			NSImage* image = [[[NSImage alloc] initWithSize:[rep size]] autorelease];
+			[image setFlipped:YES];
+			[image addRepresentation:rep];
+			[self setDivider:image];
+		} else {
+			[self setDivider:nil];
+		}
+		[self setDividerThickness:divt];
+		[self setMustAdjust];
+		[self performSelector:@selector(viewDidMoveToSuperview) withObject:nil afterDelay:0.0];
+		[self performSelector:@selector(RB___adjustOutermostIfNeeded) withObject:nil afterDelay:0.0];
+	}
+    return self;
+}
+
+@end
+
+@implementation RBSplitView (RB___ViewAdditions)
+
+// This sets the dragging status flag. After clearing the flag, the state must be saved explicitly.
+- (void)RB___setDragging:(BOOL)flag {
+	BOOL save = isDragging&&!flag;
+	isDragging = flag;
+	if (save) {
+		[self saveState:NO];
+	}
+}
+
+// This returns the number of visible subviews.
+- (unsigned int)RB___numberOfSubviews {
+	unsigned int result = 0;
+	NSEnumerator* enumerator = [[self subviews] objectEnumerator];
+	RBSplitSubview* sub;
+	while ((sub = [enumerator nextObject])) {
+		++result;
+	}
+	return result;
+}
+
+// This returns the origin coordinate of the Nth divider.
+- (float)RB___dividerOrigin:(int)indx {
+	float result = 0.0;
+	if (dividers) {
+		BOOL ishor = [self isHorizontal];
+		result = DIM(dividers[indx].origin);
+	}
+	return result;
+}
+
+// This returns an array with all non-hidden subviews.
+- (NSArray*)RB___subviews {
+	NSMutableArray* result = [NSMutableArray arrayWithArray:[self subviews]];
+	int i;
+	for (i=[result count]-1;i>=0;i--) {
+		RBSplitSubview* view = [result objectAtIndex:i];
+		if ([view isHidden]) {
+			[result removeObjectAtIndex:i];
+		}
+	}
+	return result;
+}
+
+// This returns the actual value set in dividerThickness. 
+- (float)RB___dividerThickness {
+	return dividerThickness;
+}
+
+// This method returns the actual dimension occupied by the subviews; that is, without dividers.
+- (float)RB___dimensionWithoutDividers {
+	BOOL ishor = [self isHorizontal];
+	NSSize size = [self frame].size;
+	return fMAX(1.0,DIM(size)-[self dividerThickness]*([self RB___numberOfSubviews]-1));
+}
+
+// This method returns one of the divider rectangles, or NSZeroRect if the index is invalid.
+// If view is non-nil, the rect will be expressed in that view's coordinates. We assume
+// that view is a superview of self.
+- (NSRect)RB___dividerRect:(unsigned)indx relativeToView:(RBSplitView*)view {
+	if (dividers&&(indx<[self RB___numberOfSubviews]-1)) {
+		NSRect result = dividers[indx];
+		if (view&&(view!=self)) {
+			result = [self convertRect:result toView:view];
+		}
+		return result;
+	}
+	return NSZeroRect;
+}
+
+// Returns the index of the divider hit by the point, or NSNotFound if none.
+// point is in coordinates relative to view. delta is the divider thickness added
+// to both ends of the divider rect, to accomodate two-axis thumbs.
+- (unsigned)RB___dividerHitBy:(NSPoint)point relativeToView:(RBSplitView*)view thickness:(float)delta {
+	if (!dividers) {
+		return NSNotFound;
+	}
+	int divcount = [self RB___numberOfSubviews]-1;
+	if (divcount<1) {
+		return NSNotFound;
+	}
+	int i;
+	BOOL ishor = [self isHorizontal];
+	point = [self convertPoint:point fromView:view];
+	for (i=0;i<divcount;i++) {
+		NSRect divdr = dividers[i];
+		OTHER(divdr.origin) -= delta;
+		OTHER(divdr.size) += 2*delta;
+		if ([self mouse:point inRect:divdr]) {
+			return i;
+		}
+	}
+	return NSNotFound;
+}
+
+// This method sets a flag to clear all fractions before adjusting.
+- (void)RB___setMustClearFractions {
+	mustClearFractions = YES;
+}
+
+// This local method asks the delegate if we should resize the trailing subview or the window
+// when a divider is dragged. Not called if we're inside an NSScrollView.
+- (BOOL)RB___shouldResizeWindowForDivider:(unsigned int)indx betweenView:(RBSplitSubview*)leading andView:(RBSplitSubview*)trailing willGrow:(BOOL)grow {
+	if (!isInScrollView&&[delegate respondsToSelector:@selector(splitView:shouldResizeWindowForDivider:betweenView:andView:willGrow:)]) {
+		return [delegate splitView:self shouldResizeWindowForDivider:indx betweenView:leading andView:trailing willGrow:grow];
+	}
+	return NO;
+}
+
+// This local method tries to expand the leading subview (which is assumed to be collapsed). Delta should be positive.
+- (void)RB___tryToExpandLeading:(RBSplitSubview*)leading divider:(unsigned int)indx trailing:(RBSplitSubview*)trailing delta:(float)delta {
+	NSWindow* window = nil;
+	NSView* document = nil;
+	NSSize maxsize = NSMakeSize(WAYOUT,WAYOUT);
+	NSRect frame = NSZeroRect;
+	NSRect screen = NSMakeRect(0,0,WAYOUT,WAYOUT);
+	BOOL ishor = NO;
+// First we ask the delegate, if there's any, if the window should resize.
+	BOOL dowin = ([self RB___shouldResizeWindowForDivider:indx betweenView:leading andView:trailing willGrow:YES]);
+	if (dowin) {
+// We initialize the other local variables only if we need them for the window.
+		ishor = [self isHorizontal];
+		document = [[self enclosingScrollView] documentView];
+		if (document) {
+			frame = [document frame];
+		} else {
+			window = [self window];
+			frame = [window frame];
+			maxsize = [window maxSize];
+			screen = [[NSScreen mainScreen] visibleFrame];
+		}
+	}
+// The mouse has to move over half of the expanded size (plus hysteresis) and the expansion shouldn't
+// reduce the trailing subview to less than its minimum size (or grow the window beyond its maximum).
+	float limit = [leading minDimension];
+	float dimension = 0.0;
+	if (dowin) {
+		float maxd = fMAX(0.0,(ishor?frame.origin.y-screen.origin.y:(screen.origin.x+screen.size.width)-(frame.origin.x+frame.size.width)));
+		dimension = fMIN(DIM(maxsize)-DIM(frame.size),maxd);
+	} else {
+		dimension = trailing?[trailing dimension]:WAYOUT;
+	}
+	if (limit>dimension) {
+		return;
+	}
+	if (!dowin&&trailing) {
+		limit += [trailing minDimension];
+		if (limit>dimension) {
+// If the trailing subview is going below its minimum, we try to collapse it first.
+// However, we don't collapse if that would cause the leading subview to become larger than its maximum.
+			if (([trailing canCollapse])&&(delta>(0.5+HYSTERESIS)*dimension)&&([leading maxDimension]<=dimension)) {
+				delta = -[trailing RB___collapse];
+				[leading changeDimensionBy:delta mayCollapse:NO move:NO];
+			}
+			return;
+		}
+	}
+// The leading subview may be expanded normally.
+	delta = -[leading changeDimensionBy:delta mayCollapse:NO move:NO];
+	if (dowin) {
+// If it does expand, we widen the window.
+		DIM(frame.size) -= delta;
+		if (ishor) {
+			DIM(frame.origin) += delta;
+		}
+		if (document) {
+			[document setFrame:frame];
+			[document setNeedsDisplay:YES];
+		} else {
+			[window setFrame:frame display:YES];
+		}
+		[self setMustAdjust];
+	} else {
+// If it does expand, we shorten the trailing subview.
+		[trailing changeDimensionBy:delta mayCollapse:NO move:YES];
+	}
+}
+
+// This local method tries to shorten the leading subview. Both subviews are assumed to be expanded.
+// delta should be negative. If always is NO, the subview will be shortened only if it might also be
+// collapsed; otherwise, it's shortened as much as possible.
+- (void)RB___tryToShortenLeading:(RBSplitSubview*)leading divider:(unsigned int)indx trailing:(RBSplitSubview*)trailing delta:(float)delta always:(BOOL)always {
+	NSWindow* window = nil;
+	NSView* document = nil;
+	NSSize minsize = NSZeroSize;
+	NSRect frame = NSZeroRect;
+	BOOL ishor = NO;
+// First we ask the delegate, if there's any, if the window should resize.
+	BOOL dowin = ([self RB___shouldResizeWindowForDivider:indx betweenView:leading andView:trailing willGrow:NO]);
+	if (dowin) {
+// We initialize the other local variables only if we need them for the window.
+		ishor = [self isHorizontal];
+		document = [[self enclosingScrollView] documentView];
+		if (document) {
+			frame = [document frame];
+		} else {
+			window = [self window];
+			frame = [window frame];
+			minsize = [window minSize];
+		}
+	}
+// We avoid making the trailing subview larger than its maximum, or the window smaller than its minimum.
+	float limit = 0.0;
+	if (dowin) {
+		limit = DIM(frame.size)-DIM(minsize);
+	} else {
+		limit = trailing?([trailing maxDimension]-[trailing dimension]):WAYOUT;
+	}
+	if (-delta>limit) {
+		if (always) {
+			delta = -limit;
+		} else {
+			return;
+		}
+	}
+	BOOL okl = limit>=[leading dimension];
+	if (always||okl) {
+// Resize leading.
+		delta = -[leading changeDimensionBy:delta mayCollapse:okl move:NO];
+		if (dowin) {
+// Resize the window.
+			DIM(frame.size) -= delta;
+			if (ishor) {
+				DIM(frame.origin) += delta;
+			}
+			if (document) {
+				[document setFrame:frame];
+				[document setNeedsDisplay:YES];
+			} else {
+				[window setFrame:frame display:YES];
+			}
+			[self setMustAdjust];
+		} else {
+// Otherwise, resize trailing.
+			[trailing changeDimensionBy:delta mayCollapse:NO move:YES];
+		}
+	}
+}
+
+// This local method tries to shorten the trailing subview. Both subviews are assumed to be expanded.
+// delta should be positive. If always is NO, the subview will be shortened only if it might also be
+// collapsed; otherwise, it's shortened as much as possible.
+- (void)RB___tryToShortenTrailing:(RBSplitSubview*)trailing divider:(unsigned int)indx leading:(RBSplitSubview*)leading delta:(float)delta always:(BOOL)always {
+	NSWindow* window = nil;
+	NSView* document = nil;
+	NSSize maxsize = NSMakeSize(WAYOUT,WAYOUT);
+	NSRect frame = NSZeroRect;
+	NSRect screen = NSMakeRect(0,0,WAYOUT,WAYOUT);
+	BOOL ishor = NO;
+// First we ask the delegate, if there's any, if the window should resize.
+	BOOL dowin = ([self RB___shouldResizeWindowForDivider:indx betweenView:leading andView:trailing willGrow:YES]);
+	if (dowin) {
+// We initialize the other local variables only if we need them for the window.
+		ishor = [self isHorizontal];
+		document = [[self enclosingScrollView] documentView];
+		if (document) {
+			frame = [document frame];
+		} else {
+			window = [self window];
+			frame = [window frame];
+			maxsize = [window maxSize];
+			screen = [[NSScreen mainScreen] visibleFrame];
+		}
+	}
+// We avoid making the leading subview larger than its maximum, or the window larger than its maximum.
+	float limit = 0.0;
+	if (dowin) {
+		float maxd = fMAX(0.0,(ishor?frame.origin.y-screen.origin.y:(screen.origin.x+screen.size.width)-(frame.origin.x+frame.size.width)));
+		limit = fMIN(DIM(maxsize)-DIM(frame.size),maxd);
+	} else {
+		limit = [leading maxDimension]-[leading dimension];
+	}
+	if (delta>limit) {
+		if (always) {
+			delta = limit;
+		} else {
+			return;
+		}
+	}
+	BOOL okl = dowin||(limit>=(trailing?[trailing dimension]:WAYOUT));
+	if (always||okl) {
+		if (dowin) {
+// If we should resize the window, resize leading, then the window.
+			delta = [leading changeDimensionBy:delta mayCollapse:NO move:NO];
+			DIM(frame.size) += delta;
+			if (ishor) {
+				DIM(frame.origin) -= delta;
+			}
+			if (document) {
+				[document setFrame:frame];
+				[document setNeedsDisplay:YES];
+			} else {
+				[window setFrame:frame display:YES];
+			}
+			[self setMustAdjust];
+		} else {
+// Otherwise, resize trailing, then leading.
+			if (trailing) {
+				delta = -[trailing changeDimensionBy:-delta mayCollapse:okl move:YES];
+			}
+			[leading changeDimensionBy:delta mayCollapse:NO move:NO];
+		}
+	}
+}
+
+// This method tries to expand the trailing subview (which is assumed to be collapsed).
+- (void)RB___tryToExpandTrailing:(RBSplitSubview*)trailing leading:(RBSplitSubview*)leading delta:(float)delta {
+// The mouse has to move over half of the expanded size (plus hysteresis) and the expansion shouldn't
+// reduce the leading subview to less than its minimum size. If it does, we try to collapse it first.
+// However, we don't collapse if that would cause the trailing subview to become larger than its maximum.
+	float limit = trailing?[trailing minDimension]:0.0;
+	float dimension = [leading dimension];
+	if (limit>dimension) {
+		return;
+	}
+	limit += [leading minDimension];
+	if (limit>dimension) {
+		if ([leading canCollapse]&&(-delta>(0.5+HYSTERESIS)*dimension)&&((trailing?[trailing maxDimension]:0.0)<=dimension)) {
+			delta = -[leading RB___collapse];
+			[trailing changeDimensionBy:delta mayCollapse:NO move:YES];
+		}
+		return;
+	}
+// The trailing subview may be expanded normally. If it does expand, we shorten the leading subview.
+	if (trailing) {
+		delta = -[trailing changeDimensionBy:-delta mayCollapse:NO move:YES];
+	}
+	[leading changeDimensionBy:delta mayCollapse:NO move:NO];
+}
+
+
+// This method is called by the mouseDown:method for every tracking event. It's separated out as it's
+// called from the Interface Builder palette in a slightly different way, and also if you have a
+// separate drag view designated by the delegate. You'll never need to call this directly.
+// theEvent is the event (which should be a NSLeftMouseDragged event).
+// where is the point where the original mouse-down happened, corrected for the current divider position,
+// and expressed in local coordinates.
+// base is an offset (x,y) applied to the mouse location (usually will be zero)
+// indx is the number of the divider that's being dragged.
+- (void)RB___trackMouseEvent:(NSEvent*)theEvent from:(NSPoint)where withBase:(NSPoint)base inDivider:(unsigned)indx {
+	NSPoint result;
+	NSArray* subviews = [self RB___subviews];
+	int subcount = [subviews count];
+	int k;
+// leading and trailing point at the subviews immediately leading and trailing the divider being tracked
+	RBSplitSubview* leading = [subviews objectAtIndex:indx];
+	RBSplitSubview* trailing = [subviews objectAtIndex:indx+1];
+// convert the mouse coordinates to apply to the same system the divider rects are in.
+	NSPoint mouse = [self convertPoint:[theEvent locationInWindow] fromView:nil];
+	mouse.x -= base.x;
+	mouse.y -= base.y;
+	result.x = mouse.x-where.x;
+	result.y = mouse.y-where.y;
+// delta is the actual amount the mouse has moved in the relevant coordinate since the last event.
+	BOOL ishor = [self isHorizontal];
+	float delta = DIM(result);
+	if (delta<0.0) {
+// Negative delta means the mouse is being moved left or upwards.
+// firstLeading will point at the first expanded subview to the left (or upwards) of the divider.
+// If there's none (all subviews are collapsed) it will point at the nearest subview.
+		RBSplitSubview* firstLeading = leading;
+		k = indx;
+		while (![firstLeading canShrink]) {
+			if (--k<0) {
+				firstLeading = leading;
+				break;
+			}
+			firstLeading = [subviews objectAtIndex:k];
+		}
+		if (isInScrollView) {
+			trailing = nil;
+		}
+// If the trailing subview is collapsed, it might be expanded if some conditions are met.
+		if ([trailing isCollapsed]) {
+			[self RB___tryToExpandTrailing:trailing leading:firstLeading delta:delta];
+		} else {
+			[self RB___tryToShortenLeading:firstLeading divider:indx trailing:trailing delta:delta always:YES];
+		}
+	} else if (delta>0.0) {
+// Positive delta means the mouse is being moved right or downwards.
+// firstTrailing will point at the first expanded subview to the right (or downwards) of the divider.
+// If there's none (all subviews are collapsed) it will point at the nearest subview.
+		RBSplitSubview* firstTrailing = nil;
+		if (!isInScrollView) {
+			firstTrailing = trailing;
+			k = indx+1;
+			while (![firstTrailing canShrink]) {
+				if (++k>=subcount) {
+					firstTrailing = trailing;
+					break;
+				}
+				firstTrailing = [subviews objectAtIndex:k];
+			}
+		}
+// If the leading subview is collapsed, it might be expanded if some conditions are met.
+		if ([leading isCollapsed]) {
+			[self RB___tryToExpandLeading:leading divider:indx trailing:firstTrailing delta:delta];
+		} else {
+// The leading subview is not collapsed, so we try to shorten or even collapse it
+			[self RB___tryToShortenTrailing:firstTrailing divider:indx leading:leading delta:delta always:YES];
+		}
+	}
+}
+
+// This is called for nested RBSplitViews, to add the cursor rects for the two-axis thumbs.
+- (void)RB___addCursorRectsTo:(RBSplitView*)masterView forDividerRect:(NSRect)rect thickness:(float)delta {
+	if (dividers&&[self divider]) {
+		NSArray* subviews = [self RB___subviews];
+		int divcount = [subviews count]-1;
+		if (divcount<1) {
+			return;
+		}
+		int i;
+		NSCursor* cursor = [RBSplitView cursor:RBSV2WayCursor];
+		BOOL ishor = [self isHorizontal];
+// Loop over the divider rectangles, intersect them with the view's own, and add the thumb rectangle
+// to the containing split view.
+		for (i=0;i<divcount;i++) {
+			NSRect divdr = dividers[i];
+			divdr.origin = [self convertPoint:divdr.origin toView:masterView];
+			OTHER(divdr.origin) -= delta;
+			OTHER(divdr.size) += 2*delta;
+			divdr = NSIntersectionRect(divdr,rect);
+			if (!NSIsEmptyRect(divdr)) {
+				[masterView addCursorRect:divdr cursor:cursor];
+			}
+		}
+	}
+}
+
+// This is called for nested RBSplitViews, to draw the two-axis thumbs.
+- (void)RB___drawDividersIn:(RBSplitView*)masterView forDividerRect:(NSRect)rect thickness:(float)delta {
+	if (!dividers) {
+		return;
+	}
+	NSArray* subviews = [self RB___subviews];
+	int divcount = [subviews count]-1;
+	if (divcount<1) {
+		return;
+	}
+	int i;
+	BOOL ishor = [self isHorizontal];
+// Get the outer split view's divider image.
+	NSImage* image = [masterView divider];
+// Loop over the divider rectangles, intersect them with the view's own, and draw the thumb there.
+	for (i=0;i<divcount;i++) {
+		NSRect divdr = dividers[i];
+		divdr.origin = [self convertPoint:divdr.origin toView:masterView];
+		OTHER(divdr.origin) -= delta;
+		OTHER(divdr.size) += 2*delta;
+		divdr = NSIntersectionRect(divdr,rect);
+		if (!NSIsEmptyRect(divdr)) {
+			[masterView drawDivider:image inRect:divdr betweenView:nil andView:nil];
+		}
+	}
+}
+
+// This is usually called from initWithCoder to ensure that the outermost RBSplitView is
+// properly adjusted when first displayed.
+- (void)RB___adjustOutermostIfNeeded {
+	RBSplitView* sv = [self splitView];
+	if (sv) {
+		[sv RB___adjustOutermostIfNeeded];
+		return;
+	}
+	if (mustAdjust&&!isAdjusting) {
+		[self adjustSubviews];
+	}
+}
+
+// Here we try to keep all subviews adjusted in as natural a manner as possible, given the constraints.
+// The main idea is to always keep the RBSplitView completely covered by dividers and subviews, have at
+// least one expanded subview, and never make a subview smaller than its minimum dimension, or larger
+// than its maximum dimension.
+// We try to account for most unusual situations but this may fail under some circumstances. YMMV.
+- (void)RB___adjustSubviewsExcepting:(RBSplitSubview*)excepting {
+	mustAdjust = NO;
+	NSArray* subviews = [self RB___subviews];
+	unsigned subcount = [subviews count];
+	if (subcount<1) {
+		return;
+	}
+	NSRect bounds = [self bounds];
+// Never adjust if the splitview itself is collapsed.
+	if ((bounds.size.width<1.0)||(bounds.size.height<1.0)) {
+		return;
+	}
+// Prevents adjustSubviews being called recursively, which unfortunately may happen otherwise.
+	if (isAdjusting) {
+		return;
+	}
+	isAdjusting = YES;
+// Tell the delegate we're about to adjust subviews.
+	if ([delegate respondsToSelector:@selector(willAdjustSubviews:)]) {
+		[delegate willAdjustSubviews:self];
+		bounds = [self bounds];
+	}
+	unsigned divcount = subcount-1;
+	if (divcount<1) {
+// No dividers at all.
+		if (dividers) {
+			free(dividers);
+			dividers = NULL;
+		}
+	} else {
+// Try to allocate or resize if we already have a dividers array.
+		unsigned long divsiz = sizeof(NSRect)*divcount;
+		dividers = dividers?reallocf(dividers,divsiz):malloc(divsiz);
+		if (!dividers) {
+			return;
+		}
+	}
+// This C array of subviewCaches is used to cache the subview information.
+	subviewCache* caches = malloc(sizeof(subviewCache)*subcount);
+	double realsize = 0.0;
+	double expsize = 0.0;
+	float newsize = 0.0;
+	float effsize = 0.0;
+	float limit;
+	subviewCache* curr;
+	unsigned int i;
+	BOOL ishor = [self isHorizontal];
+	float divt = [self dividerThickness];
+// First we loop over subviews and cache their information.
+	for (i=0;i<subcount;i++) {
+		curr = &caches[i];
+		[[subviews objectAtIndex:i] RB___copyIntoCache:curr];
+	}
+// This is a counter to limit the outer loop to three iterations (six if excepting is non-nil).
+	int sanity = excepting?-3:0;
+	while (sanity++<3) {
+// We try to accomodate the exception for the first group of loops, turn it off for the second.
+		if (sanity==1) {
+			excepting = nil;
+		}
+// newsize is the available space for actual subviews (so dividers don't count). It will be an integer.
+// Same as calling [self RB___dimensionWithoutDividers].
+		unsigned smallest = 0;
+		float smalldim = -1.0;
+		BOOL haveexp = NO;
+// Loop over subviews and sum the expanded dimensions into expsize, including fractions.
+// Also find the collapsed subview with the smallest minimum dimension.
+		for (i=0;i<subcount;i++) {
+			curr = &caches[i];
+			curr->constrain = NO;
+			if (curr->size>0.0) {
+				expsize += curr->size;
+				if (!isInScrollView) {
+// ignore fractions if we're in a NSScrollView, however.
+					expsize += curr->fraction;
+				}
+				haveexp = YES;
+			} else {
+				limit = [curr->sub minDimension];
+				if (smalldim>limit) {
+					smalldim = limit;
+					smallest = i;
+				}
+			}
+		}
+// haveexp should be YES at this point. If not, all subviews were collapsed; can't have that, so we 
+// expand the smallest subview (or the first, if all have the same minimum).
+		curr = &caches[smallest];
+		if (!haveexp) {
+			curr->size = [curr->sub minDimension];
+			curr->fraction = 0.0;
+			expsize += curr->size;
+		}
+		if (isInScrollView) {
+// If we're inside an NSScrollView, we just grow the view to accommodate the subviews, instead of 
+// the other way around.
+			DIM(bounds.size) = expsize;
+			break;
+		} else {
+// If the total dimension of all expanded subviews is less than 1.0 we set the dimension of the smallest
+// subview (which we're sure is expanded at this point) to the available space.
+			newsize = DIM(bounds.size)-divcount*divt;
+			if (expsize<1.0) {
+				curr->size = newsize;
+				curr->fraction = 0.0;
+				expsize = newsize;
+			}
+// Loop over the subviews and check if they're within the limits after scaling. We also recalculate the
+// exposed size and repeat until no more subviews hit the constraints during that loop.
+			BOOL constrained;
+			effsize = newsize;// we're caching newsize here, this is an integer.
+			do {
+// scale is the scalefactor by which all views should be scaled - assuming none have constraints.
+// It's a double to (hopefully) keep rounding errors small enough for all practical purposes.
+				double scale = newsize/expsize;
+				constrained = NO;
+				realsize = 0.0;
+				expsize = 0.0;
+				for (i=0;i<subcount;i++) {
+// Loop over the cached subview info.
+					curr = &caches[i];
+					if (curr->size>0.0) {
+// Check non-collapsed subviews only.
+						if (!curr->constrain) {
+// Check non-constrained subviews only; calculate the proposed new size.
+							float cursize = (curr->size+curr->fraction)*scale;
+// Check if we hit a limit. limit will contain either the max or min dimension, whichever was hit.
+							if (([curr->sub RB___animationData:NO resize:NO]&&((limit = curr->size)>=0.0))||
+								((curr->sub==excepting)&&((limit = [curr->sub dimension])>0.0))||
+								(cursize<(limit = [curr->sub minDimension]))||
+								(cursize>(limit = [curr->sub maxDimension]))) {
+// If we hit a limit, we mark the view and set to repeat the loop; non-constrained subviews will
+// have to be recalculated.
+								curr->constrain = constrained = YES;
+// We set the new size to the limit we hit, and subtract it from the total size to be subdivided.
+								cursize = limit;
+								curr->fraction = 0.0;
+								newsize -= cursize;
+							} else {
+// If we didn't hit a limit, we round the size to the nearest integer and recalculate the fraction. 
+								double rem = fmod(cursize,1.0);
+								cursize -= rem;
+								if (rem>0.5) {
+									++cursize;
+									--rem;
+								}
+								expsize += cursize;
+								curr->fraction = rem;
+							}
+// We store the new size in the cache.
+							curr->size = cursize;
+						}
+// And add the full size with fraction to the actual sum of all expanded subviews.
+						realsize += curr->size+curr->fraction;
+					}
+				}
+// At this point, newsize will be the sum of the new dimensions of non-constrained views.
+// expsize will be the sum of the recalculated dimensions of the same views, if any.
+// We repeat the loop if any view has been recently constrained, and if there are any
+// unconstrained views left.
+			} while (constrained&&(expsize>0.0));
+// At this point, the difference between realsize and effsize should be less than 1 pixel.
+// realsize is the total size of expanded subviews as recalculated above, and
+// effsize is the value realsize should have.
+			limit = realsize-effsize;
+			if (limit>=1.0) {
+// If realsize is larger than effsize by 1 pixel or more, we will need to collapse subviews to make room.
+// This in turn might expand previously collapsed subviews. So, we'll try collapsing constrained subviews
+// until we're back into range, and then recalculate everything from the beginning.
+				for (i=0;i<subcount;i++) {
+					curr = &caches[i];
+					if (curr->constrain&&(curr->sub!=excepting)&&([curr->sub RB___animationData:NO resize:NO]==nil)&&[curr->sub canCollapse]) {
+						realsize -= curr->size;
+						if (realsize<1.0) {
+							break;
+						}
+						curr->size = 0.0;
+						if ((realsize-effsize)<1.0) {
+							break;
+						}
+					}
+				}
+			} else if (limit<=-1.0) {
+// If realsize is smaller than effsize by 1 pixel or more, we will need to expand subviews.
+// This in turn might collapse previously expanded subviews. So, we'll try expanding collapsed subviews
+// until we're back into range, and then recalculate everything from the beginning.
+				for (i=0;i<subcount;i++) {
+					curr = &caches[i];
+					if (curr->size<=0.0) {
+						curr->size = [curr->sub minDimension];
+						curr->fraction = 0.0;
+						realsize += curr->size;
+						if ((realsize-effsize)>-1.0) {
+							break;
+						}
+					}
+				}
+			} else {
+// The difference is less than 1 pixel, meaning that in all probability our calculations are
+// exact or off by at most one pixel after rounding, so we break the loop here.
+				break;
+			}
+		}
+// After passing through the outer loop a few times, the frames may still be wrong, but there's nothing
+// else we can do about it. You probably should avoid this by some other means like setting a minimum
+// or maximum size for the window, for instance, or leaving at least one unlimited subview.
+	}
+// newframe is used to reset all subview frames. Subviews always fill the entire RBSplitView along the
+// current orientation.
+	NSRect newframe = NSMakeRect(0.0,0.0,bounds.size.width,bounds.size.height);
+// We now loop over the subviews yet again and set the definite frames, also recalculating the
+// divider rectangles as we go along, and collapsing and expanding subviews whenever requested.
+	RBSplitSubview* last = nil;
+// And we make a note if there's any nested RBSplitView.
+	int nested = NSNotFound;
+	newsize = DIM(bounds.size)-divcount*divt;
+	for (i=0;i<subcount;i++) {
+		curr = &caches[i];
+// If we have a nested split view store its index.
+		if ((nested==NSNotFound)&&([curr->sub asSplitView]!=nil)) {
+			nested = i;
+		}
+// Adjust the subview to the correct origin and resize it to fit into the "other" dimension.
+		curr->rect.origin = newframe.origin;
+		OTHER(curr->rect.size) = OTHER(newframe.size);
+		DIM(curr->rect.size) = curr->size;
+// Clear fractions for expanded subviews if requested.
+		if ((curr->size>0.0)&&mustClearFractions) {
+			curr->fraction = 0.0;
+		}
+// Ask the subview to do the actual moving/resizing etc. from the cache.
+		[curr->sub RB___updateFromCache:curr withTotalDimension:effsize];
+// Step to the next position and record the subview if it's not collapsed.
+		DIM(newframe.origin) += curr->size;
+		if (curr->size>0.0) {
+			last = curr->sub;
+		}
+		if (i==divcount) {
+// We're at the last subview, so we now check if the actual and calculated dimensions
+// are the same.
+			float remain = DIM(bounds.size)-DIM(newframe.origin);
+			if (last&&(fabsf(remain)>0.0)) {
+// We'll resize the last expanded subview to whatever it takes to squeeze within the frame.
+// Normally the change should be at most one pixel, but if too many subviews were constrained,
+// this may be a large value, and the last subview may be resized beyond its constraints;
+// there's nothing else to do at this point.
+				newframe = [last frame];
+				DIM(newframe.size) += remain;
+				[last RB___setFrameSize:newframe.size withFraction:[last RB___fraction]-remain];
+// And we loop back over the rightmost dividers (if any) to adjust their offsets.
+				while ((i>0)&&(last!=[subviews objectAtIndex:i])) {
+					DIM(dividers[--i].origin) += remain;
+				}
+				break;
+			}
+		} else {
+// For any but the last subview, we just calculate the divider frame.
+			DIM(newframe.size) = divt;
+			dividers[i] = newframe;
+			DIM(newframe.origin) += divt;
+		}
+	}
+// We resize our frame at this point, if we're inside an NSScrollView.
+	if (isInScrollView) {
+		[super setFrameSize:bounds.size];
+	}
+// If there was at least one nested RBSplitView, we loop over the subviews and adjust those that need it.
+	for (i=nested;i<subcount;i++) {
+		curr = &caches[i];
+		RBSplitView* sv = [curr->sub asSplitView];
+		if ([sv mustAdjust]) {
+			[sv adjustSubviews];
+		}
+	}
+// Free the cache array.
+	free(caches);
+// Clear cursor rects.
+	mustAdjust = NO;
+	mustClearFractions = NO;
+	[[self window] invalidateCursorRectsForView:self];
+// Save the state for all subviews.
+	if (!isDragging) {
+		[self saveState:NO];
+	}
+// If we're a nested RBSplitView, also invalidate cursorRects for the superview.
+	RBSplitView* sv = [self couplingSplitView];
+	if (sv) {
+		[[self window] invalidateCursorRectsForView:sv];
+	}
+	isAdjusting = NO;
+// Tell the delegate we're finished.
+	if ([delegate respondsToSelector:@selector(didAdjustSubviews:)]) {
+		[delegate didAdjustSubviews:self];
+	}
+}
+
+@end
+
diff --git a/src/MacVim/RBSplitViewPrivateDefines.h b/src/MacVim/RBSplitViewPrivateDefines.h
new file mode 100644
index 0000000..601f9ee
--- /dev/null
+++ b/src/MacVim/RBSplitViewPrivateDefines.h
@@ -0,0 +1,98 @@
+//
+//  RBSplitViewPrivateDefines.h version 1.1.4
+//  RBSplitView
+//
+//  Created by Rainer Brockerhoff on 19/11/2004.
+//  Copyright 2004-2006 Rainer Brockerhoff.
+//	Some Rights Reserved under the Creative Commons Attribution License, version 2.5, and/or the MIT License.
+//
+
+// These defines are used only locally; no sense exporting them in the main header file where they might
+// conflict with something...
+
+// This is the hysteresis value for collapsing/expanding subviews with the mouse. 0.05 (5%) works well.
+#define HYSTERESIS (0.05)
+
+// This selects the main horizontal or vertical coordinate according to the split view's orientation.
+// It can be used as an lvalue, too. You need to have BOOL ishor declared to use it.
+#define DIM(x) (((float*)&(x))[ishor])
+
+// This selects the other coordinate.
+#define OTHER(x) (((float*)&(x))[!ishor])
+
+// This value for the view offsets is guaranteed to be out of view for quite some time and is used
+// to mark the view as collapsed.
+#define WAYOUT (1000000.0)
+
+// This is the default framerate for collapse/expand animation.
+#define FRAMETIME (1.0/60.0)
+
+// This struct is used internally for speeding up adjustSubviews.
+typedef struct subviewCache {
+	NSRect rect;					// the subview's frame
+	double fraction;				// fractional extra
+	RBSplitSubview* sub;			// points at the subview
+	float size;						// current dimension (integer)
+	BOOL constrain;					// set if constrained
+} subviewCache;
+
+// This struct is used internally for doing collapse/expand animation.
+typedef struct animationData {
+	RBSplitSubview* owner;			// the subview being animated
+	float dimension;				// the subview's starting or ending dimension
+	int stepsDone;					// counts already done animation steps
+	NSTimeInterval elapsedTime;		// time already spent in resizing and adjusting subviews
+	NSTimeInterval finishTime;		// the animation should be finished at this time
+	NSTimeInterval totalTime;		// total time the animation should take
+	BOOL collapsing;				// YES if we're collapsing, NO if we're expanding
+	BOOL resizing;					// YES if we're resizing, NO if we're frozen
+} animationData;
+
+// The following methods are for internal use, and you should never call or override them.
+// They'll probably vary wildy from version to version, too.
+
+@interface RBSplitSubview (RB___SubviewAdditions)
+
+- (void)RB___setHidden:(BOOL)flag;
+- (animationData*)RB___animationData:(BOOL)start resize:(BOOL)resize;
+- (void)RB___stepAnimation;
+- (BOOL)RB___stopAnimation;
+- (float)RB___visibleDimension;
+- (float)RB___setMinAndMaxTo:(float)value savingMin:(float*)oldmin andMax:(float*)oldmax;
+- (float)RB___collapse;
+- (float)RB___expandAndSetToMinimum:(BOOL)setToMinimum;
+- (void)RB___finishCollapse:(NSRect)rect withFraction:(double)value;
+- (void)RB___finishExpand:(NSRect)rect withFraction:(double)value;
+- (void)RB___setFrameSize:(NSSize)size withFraction:(double)value;
+- (void)RB___setFrame:(NSRect)rect withFraction:(double)value notify:(BOOL)notify;
+- (double)RB___fraction;
+- (void)RB___copyIntoCache:(subviewCache*)cache;
+- (void)RB___updateFromCache:(subviewCache*)cache withTotalDimension:(float)value;
+- (BOOL)RB___clearResponder;
+
+@end
+
+@interface RBSplitView (RB___ViewAdditions)
+
+- (void)RB___adjustOutermostIfNeeded;
+- (void)RB___setDragging:(BOOL)flag;
+- (float)RB___dividerOrigin:(int)indx;
+- (NSArray*)RB___subviews;
+- (unsigned int)RB___numberOfSubviews;
+- (void)RB___adjustSubviewsExcepting:(RBSplitSubview*)excepting;
+- (float)RB___dimensionWithoutDividers;
+- (float)RB___dividerThickness;
+- (NSRect)RB___dividerRect:(unsigned)indx relativeToView:(RBSplitView*)view;
+- (void)RB___setMustClearFractions;
+- (BOOL)RB___shouldResizeWindowForDivider:(unsigned int)indx betweenView:(RBSplitSubview*)leading andView:(RBSplitSubview*)trailing willGrow:(BOOL)grow;
+- (void)RB___tryToExpandLeading:(RBSplitSubview*)leading divider:(unsigned int)indx trailing:(RBSplitSubview*)trailing delta:(float)delta;
+- (void)RB___tryToShortenLeading:(RBSplitSubview*)leading divider:(unsigned int)indx trailing:(RBSplitSubview*)trailing delta:(float)delta always:(BOOL)always;
+- (void)RB___tryToExpandTrailing:(RBSplitSubview*)trailing leading:(RBSplitSubview*)leading delta:(float)delta;
+- (void)RB___tryToShortenTrailing:(RBSplitSubview*)trailing divider:(unsigned int)indx leading:(RBSplitSubview*)leading delta:(float)delta always:(BOOL)always;
+- (void)RB___trackMouseEvent:(NSEvent*)theEvent from:(NSPoint)where withBase:(NSPoint)base inDivider:(unsigned)indx;
+- (void)RB___addCursorRectsTo:(RBSplitView*)masterView forDividerRect:(NSRect)rect thickness:(float)delta;
+- (unsigned)RB___dividerHitBy:(NSPoint)point relativeToView:(RBSplitView*)view thickness:(float)delta;
+- (void)RB___drawDividersIn:(RBSplitView*)masterView forDividerRect:(NSRect)rect thickness:(float)delta;
+
+@end
+
-- 
1.5.5.1

