//// BWSplitView.m// BWToolkit//// Created by Brandon Walkin (www.brandonwalkin.com) and Fraser Kuyvenhoven.// All code is provided under the New BSD license.//#import "BWSplitView.h"#import "BWAnchoredButtonBar.h"#import "NSColor+BWAdditions.h"#import "NSEvent+BWAdditions.h"staticNSGradient*gradient;staticNSImage*dimpleImageBitmap,*dimpleImageVector;staticNSColor*borderColor,*gradientStartColor,*gradientEndColor;staticfloatscaleFactor=1.0f;#define dimpleDimension 4.0f#define RESIZE_DEBUG_LOGS 0@interfaceBWSplitView(BWSVPrivate)-(void)drawDimpleInRect:(NSRect)aRect;-(void)drawGradientDividerInRect:(NSRect)aRect;-(int)resizableSubviews;-(BOOL)subviewIsResizable:(NSView*)subview;-(BOOL)subviewIsCollapsible:(NSView*)subview;-(BOOL)subviewIsCollapsed:(NSView*)subview;-(int)collapsibleSubviewIndex;-(NSView*)collapsibleSubview;-(BOOL)hasCollapsibleSubview;-(BOOL)collapsibleSubviewIsCollapsed;-(CGFloat)subviewMinimumSize:(int)subviewIndex;-(CGFloat)subviewMaximumSize:(int)subviewIndex;-(void)recalculatePreferredProportionsAndSizes;-(BOOL)validatePreferredProportionsAndSizes;-(void)validateAndCalculatePreferredProportionsAndSizes;-(void)clearPreferredProportionsAndSizes;-(void)saveUncollapsedSizes;-(void)restoreUncollapsedSizes;-(void)resizeAndAdjustSubviews;@end@interfaceBWSplitView()@propertyBOOLcheckboxIsEnabled;@end@implementationBWSplitView@synthesizecolor,colorIsEnabled,checkboxIsEnabled,minValues,maxValues,minUnits,maxUnits,collapsiblePopupSelection,dividerCanCollapse,collapsibleSubviewCollapsed;@synthesizeresizableSubviewPreferredProportion,nonresizableSubviewPreferredSize,stateForLastPreferredCalculations;@synthesizetoggleCollapseButton,secondaryDelegate;+(void)initialize;{borderColor=[[NSColorcolorWithCalibratedWhite:(165.0f/255.0f)alpha:1]retain];gradientStartColor=[[NSColorcolorWithCalibratedWhite:(253.0f/255.0f)alpha:1]retain];gradientEndColor=[[NSColorcolorWithCalibratedWhite:(222.0f/255.0f)alpha:1]retain];gradient=[[NSGradientalloc]initWithStartingColor:gradientStartColorendingColor:gradientEndColor];NSBundle*bundle=[NSBundlebundleForClass:[BWSplitViewclass]];dimpleImageBitmap=[[NSImagealloc]initWithContentsOfFile:[bundlepathForImageResource:@"GradientSplitViewDimpleBitmap.tif"]];dimpleImageVector=[[NSImagealloc]initWithContentsOfFile:[bundlepathForImageResource:@"GradientSplitViewDimpleVector.pdf"]];[dimpleImageBitmapsetFlipped:YES];[dimpleImageVectorsetFlipped:YES];}-(id)initWithCoder:(NSCoder*)decoder;{if((self=[superinitWithCoder:decoder])!=nil){[selfsetColor:[decoderdecodeObjectForKey:@"BWSVColor"]];[selfsetColorIsEnabled:[decoderdecodeBoolForKey:@"BWSVColorIsEnabled"]];[selfsetMinValues:[decoderdecodeObjectForKey:@"BWSVMinValues"]];[selfsetMaxValues:[decoderdecodeObjectForKey:@"BWSVMaxValues"]];[selfsetMinUnits:[decoderdecodeObjectForKey:@"BWSVMinUnits"]];[selfsetMaxUnits:[decoderdecodeObjectForKey:@"BWSVMaxUnits"]];[selfsetCollapsiblePopupSelection:[decoderdecodeIntForKey:@"BWSVCollapsiblePopupSelection"]];[selfsetDividerCanCollapse:[decoderdecodeBoolForKey:@"BWSVDividerCanCollapse"]];// Delegate set in nib has been decoded, but we want that to be the secondary delegate[selfsetDelegate:[superdelegate]];[supersetDelegate:self];}returnself;}-(void)encodeWithCoder:(NSCoder*)coder{// Temporarily change delegate[supersetDelegate:secondaryDelegate];[superencodeWithCoder:coder];[coderencodeObject:[selfcolor]forKey:@"BWSVColor"];[coderencodeBool:[selfcolorIsEnabled]forKey:@"BWSVColorIsEnabled"];[coderencodeObject:[selfminValues]forKey:@"BWSVMinValues"];[coderencodeObject:[selfmaxValues]forKey:@"BWSVMaxValues"];[coderencodeObject:[selfminUnits]forKey:@"BWSVMinUnits"];[coderencodeObject:[selfmaxUnits]forKey:@"BWSVMaxUnits"];[coderencodeInt:[selfcollapsiblePopupSelection]forKey:@"BWSVCollapsiblePopupSelection"];[coderencodeBool:[selfdividerCanCollapse]forKey:@"BWSVDividerCanCollapse"];// Set delegate back[selfsetDelegate:[superdelegate]];[supersetDelegate:self];}-(void)awakeFromNib{uncollapsedSizes=[[NSMutableArrayalloc]init];scaleFactor=[[NSScreenmainScreen]userSpaceScaleFactor];}-(void)drawDividerInRect:(NSRect)aRect{if([selfdividerThickness]<1.01){if(colorIsEnabled&&color!=nil)[colordrawSwatchInRect:aRect];else[superdrawDividerInRect:aRect];}else{[selfdrawGradientDividerInRect:aRect];}}-(void)drawGradientDividerInRect:(NSRect)aRect{aRect=[selfcenterScanRect:aRect];if([selfisVertical]){// Draw gradientNSRectgradRect=NSMakeRect(aRect.origin.x+1/scaleFactor,aRect.origin.y,aRect.size.width-1/scaleFactor,aRect.size.height);[gradientdrawInRect:gradRectangle:0];// Draw left and right borders[borderColorbwDrawPixelThickLineAtPosition:0withInset:0inRect:aRectinView:selfhorizontal:NOflip:NO];[borderColorbwDrawPixelThickLineAtPosition:0withInset:0inRect:aRectinView:selfhorizontal:NOflip:YES];}else{// Draw gradientNSRectgradRect=NSMakeRect(aRect.origin.x,aRect.origin.y+1/scaleFactor,aRect.size.width,aRect.size.height-1/scaleFactor);[gradientdrawInRect:gradRectangle:90];// Draw top and bottom borders[borderColorbwDrawPixelThickLineAtPosition:0withInset:0inRect:aRectinView:selfhorizontal:YESflip:NO];[borderColorbwDrawPixelThickLineAtPosition:0withInset:0inRect:aRectinView:selfhorizontal:YESflip:YES];}[selfdrawDimpleInRect:aRect];}-(void)drawDimpleInRect:(NSRect)aRect{floatstartY=aRect.origin.y+roundf((aRect.size.height/2)-(dimpleDimension/2));floatstartX=aRect.origin.x+roundf((aRect.size.width/2)-(dimpleDimension/2));NSRectdestRect=NSMakeRect(startX,startY,dimpleDimension,dimpleDimension);// Draw at pixel bounds destRect=[selfconvertRectToBase:destRect];destRect.origin.x=floor(destRect.origin.x);doubleparam,fractPart,intPart;param=destRect.origin.y;fractPart=modf(param,&intPart);if(fractPart<0.99)destRect.origin.y=floor(destRect.origin.y);destRect=[selfconvertRectFromBase:destRect];if(scaleFactor==1){NSRectdimpleRect=NSMakeRect(0,0,dimpleDimension,dimpleDimension);[dimpleImageBitmapdrawInRect:destRectfromRect:dimpleRectoperation:NSCompositeSourceOverfraction:1];}else{NSRectdimpleRect=NSMakeRect(0,0,[dimpleImageVectorsize].width,[dimpleImageVectorsize].height);[dimpleImageVectordrawInRect:destRectfromRect:dimpleRectoperation:NSCompositeSourceOverfraction:1];}}-(void)setDelegate:(id)anObj{if(secondaryDelegate!=self)secondaryDelegate=anObj;elsesecondaryDelegate=nil;}-(BOOL)subviewIsCollapsible:(NSView*)subview;{// check if this is the collapsible subviewintsubviewIndex=[[selfsubviews]indexOfObject:subview];BOOLisCollapsibleSubview=(([selfcollapsiblePopupSelection]==1&&subviewIndex==0)||([selfcollapsiblePopupSelection]==2&&subviewIndex==[[selfsubviews]count]-1));returnisCollapsibleSubview;}-(BOOL)subviewIsCollapsed:(NSView*)subview;{BOOLisCollapsibleSubview=[selfsubviewIsCollapsible:subview];return[superisSubviewCollapsed:subview]||(isCollapsibleSubview&&collapsibleSubviewCollapsed);}-(BOOL)collapsibleSubviewIsCollapsed;{return[selfsubviewIsCollapsed:[selfcollapsibleSubview]];}-(int)collapsibleSubviewIndex;{switch([selfcollapsiblePopupSelection]){case1:return0;break;case2:return[[selfsubviews]count]-1;break;default:return-1;break;}}-(NSView*)collapsibleSubview;{intindex=[selfcollapsibleSubviewIndex];if(index>=0)return[[selfsubviews]objectAtIndex:index];elsereturnnil;}-(BOOL)hasCollapsibleSubview;{if([selfrespondsToSelector:@selector(ibDidAddToDesignableDocument:)])returnNO;return[selfcollapsiblePopupSelection]!=0;}// This is done to support the use of Core Animation to collapse subviews-(void)adjustSubviews{[superadjustSubviews];[[selfwindow]invalidateCursorRectsForView:self];}-(void)setCollapsibleSubviewCollapsedHelper:(NSNumber*)flag{[selfsetCollapsibleSubviewCollapsed:[flagboolValue]];}-(void)animationEnded{isAnimating=NO;}-(float)animationDuration{if([NSEventbwShiftKeyIsDown])return2.0;return0.25;}-(BOOL)hasCollapsibleDivider{if([selfhasCollapsibleSubview]&&(dividerCanCollapse||[selfdividerThickness]<1.01))returnYES;returnNO;}-(int)collapsibleDividerIndex{if([selfhasCollapsibleDivider]){if([selfcollapsiblePopupSelection]==1)return0;elseif([selfcollapsiblePopupSelection]==2)return[selfsubviews].count-2;}return-1;}-(void)setCollapsibleSubviewCollapsed:(BOOL)flag{collapsibleSubviewCollapsed=flag;if(flag)[[selftoggleCollapseButton]setState:0];else[[selftoggleCollapseButton]setState:1];}-(void)setMinSizeForCollapsibleSubview:(NSNumber*)minSize{if([selfhasCollapsibleSubview]){NSMutableDictionary*tempMinValues=[[[selfminValues]mutableCopy]autorelease];[tempMinValuessetObject:minSizeforKey:[NSNumbernumberWithInt:[[selfsubviews]indexOfObject:[selfcollapsibleSubview]]]];[selfsetMinValues:tempMinValues];}}-(void)removeMinSizeForCollapsibleSubview{if([selfhasCollapsibleSubview]){NSMutableDictionary*tempMinValues=[[[selfminValues]mutableCopy]autorelease];[tempMinValuesremoveObjectForKey:[NSNumbernumberWithInt:[[selfsubviews]indexOfObject:[selfcollapsibleSubview]]]];[selfsetMinValues:tempMinValues];}}-(void)restoreAutoresizesSubviews:(NSNumber*)flag{[[selfcollapsibleSubview]setAutoresizesSubviews:[flagboolValue]];}-(IBAction)toggleCollapse:(id)sender{if([selfrespondsToSelector:@selector(ibDidAddToDesignableDocument:)])return;if([selfhasCollapsibleSubview]==NO||[selfcollapsibleSubview]==nil)return;if(isAnimating)return;// Check to see if the collapsible subview has a minimum width/height and record it.// We'll later remove the min size temporarily while animating and then restore it.BOOLhasMinSize=NO;NSNumber*minSize=[minValuesobjectForKey:[NSNumbernumberWithInt:[[selfsubviews]indexOfObject:[selfcollapsibleSubview]]]];minSize=[[minSizecopy]autorelease];if(minSize!=nil||[minSizeintValue]!=0)hasMinSize=YES;// Get a reference to the button and modify its behaviorif([selftoggleCollapseButton]==nil){[selfsetToggleCollapseButton:sender];[[toggleCollapseButtoncell]setHighlightsBy:NSPushInCellMask];[[toggleCollapseButtoncell]setShowsStateBy:NSContentsCellMask];}// Temporary: For simplicty, there should only be 1 subview other than the collapsible subview that's resizable for the collapse to happenNSView*resizableSubview=nil;for(NSView*subviewin[selfsubviews]){if([selfsubviewIsResizable:subview]&&subview!=[selfcollapsibleSubview]){resizableSubview=subview;}}if(resizableSubview==nil)return;// Record whether the collapsible subview is set to autoresize subviews so we can restore it after the animationBOOLautoresizesSubviews=[[selfcollapsibleSubview]autoresizesSubviews];// Turn off autoresizesSubviews on the collapsible subview[[selfcollapsibleSubview]setAutoresizesSubviews:NO];// Get the thickness of the collapsible divider. If the divider cannot collapse, we set it to 0 so it doesn't affect our calculations.floatcollapsibleDividerThickness=[selfdividerThickness];if([selfhasCollapsibleDivider]==NO)collapsibleDividerThickness=0;// Collapsing by dragging the divider sets the view to be hidden, so unhide it[[selfcollapsibleSubview]setHidden:NO];if([selfisVertical]){floatconstantHeight=[selfcollapsibleSubview].frame.size.height;if([selfcollapsibleSubviewCollapsed]==NO){uncollapsedSize=[selfcollapsibleSubview].frame.size.width;[selfsaveUncollapsedSizes];if(hasMinSize)[selfremoveMinSizeForCollapsibleSubview];#ifdef __APPLE__[NSAnimationContextbeginGrouping];[[NSAnimationContextcurrentContext]setDuration:([selfanimationDuration])];#endif[[[selfcollapsibleSubview]animator]setFrameSize:NSMakeSize(0.0,constantHeight)];[[resizableSubviewanimator]setFrameSize:NSMakeSize(resizableSubview.frame.size.width+uncollapsedSize+collapsibleDividerThickness,constantHeight)];#ifdef __APPLE__[NSAnimationContextendGrouping];#endifif(hasMinSize)[selfperformSelector:@selector(setMinSizeForCollapsibleSubview:)withObject:minSizeafterDelay:[selfanimationDuration]];[selfperformSelector:@selector(setCollapsibleSubviewCollapsedHelper:)withObject:[NSNumbernumberWithBool:YES]afterDelay:[selfanimationDuration]];}else{if(hasMinSize)[selfremoveMinSizeForCollapsibleSubview];[selfrestoreUncollapsedSizes];#ifdef __APPLE__ [NSAnimationContextbeginGrouping];[[NSAnimationContextcurrentContext]setDuration:([selfanimationDuration])];#endif[[[selfcollapsibleSubview]animator]setFrameSize:NSMakeSize(uncollapsedSize,constantHeight)];[[resizableSubviewanimator]setFrameSize:NSMakeSize(resizableSubview.frame.size.width-uncollapsedSize-collapsibleDividerThickness,constantHeight)];#ifdef __APPLE__[NSAnimationContextendGrouping];#endifif(hasMinSize)[selfperformSelector:@selector(setMinSizeForCollapsibleSubview:)withObject:minSizeafterDelay:[selfanimationDuration]];[selfsetCollapsibleSubviewCollapsed:NO];}}else{floatconstantWidth=[selfcollapsibleSubview].frame.size.width;if([selfcollapsibleSubviewCollapsed]==NO){uncollapsedSize=[selfcollapsibleSubview].frame.size.height;[selfsaveUncollapsedSizes];if(hasMinSize)[selfremoveMinSizeForCollapsibleSubview];#ifdef __APPLE__[NSAnimationContextbeginGrouping];[[NSAnimationContextcurrentContext]setDuration:([selfanimationDuration])];#endif[[[selfcollapsibleSubview]animator]setFrameSize:NSMakeSize(constantWidth,0.0)];[[resizableSubviewanimator]setFrameSize:NSMakeSize(constantWidth,resizableSubview.frame.size.height+uncollapsedSize+collapsibleDividerThickness)];#ifdef __APPLE__[NSAnimationContextendGrouping];#endifif(hasMinSize)[selfperformSelector:@selector(setMinSizeForCollapsibleSubview:)withObject:minSizeafterDelay:[selfanimationDuration]];[selfperformSelector:@selector(setCollapsibleSubviewCollapsedHelper:)withObject:[NSNumbernumberWithBool:YES]afterDelay:[selfanimationDuration]];}else{if(hasMinSize)[selfremoveMinSizeForCollapsibleSubview];[selfrestoreUncollapsedSizes];#ifdef __APPLE__[NSAnimationContextbeginGrouping];[[NSAnimationContextcurrentContext]setDuration:([selfanimationDuration])];#endif[[[selfcollapsibleSubview]animator]setFrameSize:NSMakeSize(constantWidth,uncollapsedSize)];[[resizableSubviewanimator]setFrameSize:NSMakeSize(constantWidth,resizableSubview.frame.size.height-uncollapsedSize-collapsibleDividerThickness)];#ifdef __APPLE__[NSAnimationContextendGrouping];#endifif(hasMinSize)[selfperformSelector:@selector(setMinSizeForCollapsibleSubview:)withObject:minSizeafterDelay:[selfanimationDuration]];[selfsetCollapsibleSubviewCollapsed:NO];}}isAnimating=YES;[selfperformSelector:@selector(animationEnded)withObject:nilafterDelay:[selfanimationDuration]+0.1];[selfperformSelector:@selector(restoreAutoresizesSubviews:)withObject:[NSNumbernumberWithBool:autoresizesSubviews]afterDelay:[selfanimationDuration]+0.1];[selfperformSelector:@selector(resizeAndAdjustSubviews)withObject:nilafterDelay:[selfanimationDuration]+0.1];}#pragma mark Mouse Tracking Methods-(void)mouseDown:(NSEvent*)theEvent{// Set the uncollapsed size whenever the split view is clicked or a drag has began. This lets us uncollapse to the size of the subview before the drag-collapse.if([selfhasCollapsibleSubview]){CGFloatcollapsibleViewSize=[selfisVertical]?[selfcollapsibleSubview].frame.size.width:[selfcollapsibleSubview].frame.size.height;if(!isAnimating&&collapsibleViewSize>0){uncollapsedSize=collapsibleViewSize;[selfsaveUncollapsedSizes];}}[supermouseDown:theEvent];}#pragma mark NSSplitView Delegate Methods-(BOOL)splitView:(NSSplitView*)splitViewshouldHideDividerAtIndex:(NSInteger)dividerIndex{if([secondaryDelegaterespondsToSelector:@selector(splitView:shouldHideDividerAtIndex:)]&&[secondaryDelegateisKindOfClass:[BWAnchoredButtonBarclass]]==NO)return[secondaryDelegatesplitView:splitViewshouldHideDividerAtIndex:dividerIndex];if([selfrespondsToSelector:@selector(ibDidAddToDesignableDocument:)]==NO){if([selfhasCollapsibleDivider]&&[selfcollapsibleDividerIndex]==dividerIndex){[selfsetDividerCanCollapse:YES];returnYES;}}returnNO;}-(NSRect)splitView:(NSSplitView*)splitViewadditionalEffectiveRectOfDividerAtIndex:(NSInteger)dividerIndex{if([secondaryDelegaterespondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)])return[secondaryDelegatesplitView:splitViewadditionalEffectiveRectOfDividerAtIndex:dividerIndex];returnNSZeroRect;}-(BOOL)splitView:(NSSplitView*)sendercanCollapseSubview:(NSView*)subview{if([secondaryDelegaterespondsToSelector:@selector(splitView:canCollapseSubview:)]&&[secondaryDelegateisKindOfClass:[BWAnchoredButtonBarclass]]==NO)return[secondaryDelegatesplitView:sendercanCollapseSubview:subview];intsubviewIndex=[[selfsubviews]indexOfObject:subview];if([selfrespondsToSelector:@selector(ibDidAddToDesignableDocument:)]==NO){if([selfcollapsiblePopupSelection]==1&&subviewIndex==0)returnYES;elseif([selfcollapsiblePopupSelection]==2&&subviewIndex==[[selfsubviews]count]-1)returnYES;}returnNO;}-(BOOL)splitView:(NSSplitView*)splitViewshouldCollapseSubview:(NSView*)subviewforDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex{if([secondaryDelegaterespondsToSelector:@selector(splitView:shouldCollapseSubview:forDoubleClickOnDividerAtIndex:)]&&[secondaryDelegateisKindOfClass:[BWAnchoredButtonBarclass]]==NO)return[secondaryDelegatesplitView:splitViewshouldCollapseSubview:subviewforDoubleClickOnDividerAtIndex:dividerIndex];intsubviewIndex=[[selfsubviews]indexOfObject:subview];if([selfrespondsToSelector:@selector(ibDidAddToDesignableDocument:)]==NO){if(([selfcollapsiblePopupSelection]==1&&subviewIndex==0&&dividerIndex==0)||([selfcollapsiblePopupSelection]==2&&subviewIndex==[[selfsubviews]count]-1&&dividerIndex==[[splitViewsubviews]count]-2)){if([selfisVertical]){uncollapsedSize=[selfcollapsibleSubview].frame.size.width;[selfsaveUncollapsedSizes];}else{uncollapsedSize=[selfcollapsibleSubview].frame.size.height;[selfsaveUncollapsedSizes];}[selfsetCollapsibleSubviewCollapsed:YES];// Cause the collapse ourselves by calling the resize method[selfresizeAndAdjustSubviews];[selfsetNeedsDisplay:YES];// Since we manually did the resize above, we pretend that we don't want to collapsereturnNO;}}returnNO;}-(CGFloat)splitView:(NSSplitView*)senderconstrainMaxCoordinate:(CGFloat)proposedMaxofSubviewAt:(NSInteger)offset{if([secondaryDelegaterespondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)]&&[secondaryDelegateisKindOfClass:[BWAnchoredButtonBarclass]]==NO)return[secondaryDelegatesplitView:senderconstrainMaxCoordinate:proposedMaxofSubviewAt:offset];// Max coordinate depends on max of subview offset, and the min of subview offset + 1CGFloatnewMaxFromThisSubview=proposedMax;CGFloatnewMaxFromNextSubview=proposedMax;// Max from this subviewCGFloatmaxValue=[selfsubviewMaximumSize:offset];if(maxValue!=FLT_MAX){NSView*subview=[[selfsubviews]objectAtIndex:offset];CGFloatoriginCoord=[selfisVertical]?[subviewframe].origin.x:[subviewframe].origin.y;newMaxFromThisSubview=originCoord+maxValue;}// Max from the next subviewintnextOffset=offset+1;if([[selfsubviews]count]>nextOffset){CGFloatminValue=[selfsubviewMinimumSize:nextOffset];if(minValue!=0){NSView*subview=[[selfsubviews]objectAtIndex:nextOffset];CGFloatendCoord=[selfisVertical]?[subviewframe].origin.x+[subviewframe].size.width:[subviewframe].origin.y+[subviewframe].size.height;newMaxFromNextSubview=endCoord-minValue-[selfdividerThickness];// This could cause trouble when over constrained (TODO)}}CGFloatnewMax=fminf(newMaxFromThisSubview,newMaxFromNextSubview);if(newMax<proposedMax)returnnewMax;returnproposedMax;}-(CGFloat)splitView:(NSSplitView*)senderconstrainMinCoordinate:(CGFloat)proposedMinofSubviewAt:(NSInteger)offset{if([secondaryDelegaterespondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)]&&[secondaryDelegateisKindOfClass:[BWAnchoredButtonBarclass]]==NO)return[secondaryDelegatesplitView:senderconstrainMinCoordinate:proposedMinofSubviewAt:offset];// Min coordinate depends on min of subview offset and the max of subview offset + 1CGFloatnewMinFromThisSubview=proposedMin;CGFloatnewMaxFromNextSubview=proposedMin;// Min from this subviewCGFloatminValue=[selfsubviewMinimumSize:offset];if(minValue!=0){NSView*subview=[[selfsubviews]objectAtIndex:offset];CGFloatoriginCoord=[selfisVertical]?[subviewframe].origin.x:[subviewframe].origin.y;newMinFromThisSubview=originCoord+minValue;}// Min from the next subviewintnextOffset=offset+1;if([[selfsubviews]count]>nextOffset){CGFloatmaxValue=[selfsubviewMaximumSize:nextOffset];if(maxValue!=FLT_MAX){NSView*subview=[[selfsubviews]objectAtIndex:nextOffset];CGFloatendCoord=[selfisVertical]?[subviewframe].origin.x+[subviewframe].size.width:[subviewframe].origin.y+[subviewframe].size.height;newMaxFromNextSubview=endCoord-maxValue-[selfdividerThickness];// This could cause trouble when over constrained (TODO)}}CGFloatnewMin=fmaxf(newMinFromThisSubview,newMaxFromNextSubview);if(newMin>proposedMin)returnnewMin;returnproposedMin;}-(CGFloat)splitView:(NSSplitView*)senderconstrainSplitPosition:(CGFloat)proposedPositionofSubviewAt:(NSInteger)offset{[selfclearPreferredProportionsAndSizes];if([selfrespondsToSelector:@selector(ibDidAddToDesignableDocument:)])returnproposedPosition;if([secondaryDelegaterespondsToSelector:@selector(splitView:constrainSplitPosition:ofSubviewAt:)]&&[secondaryDelegateisKindOfClass:[BWAnchoredButtonBarclass]]==NO)return[secondaryDelegatesplitView:senderconstrainSplitPosition:proposedPositionofSubviewAt:offset];returnproposedPosition;}-(NSRect)splitView:(NSSplitView*)splitVieweffectiveRect:(NSRect)proposedEffectiveRectforDrawnRect:(NSRect)drawnRectofDividerAtIndex:(NSInteger)dividerIndex{if([secondaryDelegaterespondsToSelector:@selector(splitView:effectiveRect:forDrawnRect:ofDividerAtIndex:)])return[secondaryDelegatesplitView:splitVieweffectiveRect:proposedEffectiveRectforDrawnRect:drawnRectofDividerAtIndex:dividerIndex];returnproposedEffectiveRect;}-(void)splitViewDidResizeSubviews:(NSNotification*)aNotification{if(collapsibleSubviewCollapsed&&([selfisVertical]?[[selfcollapsibleSubview]frame].size.width>0:[[selfcollapsibleSubview]frame].size.height>0)){[selfsetCollapsibleSubviewCollapsed:NO];[selfresizeAndAdjustSubviews];}elseif(!collapsibleSubviewCollapsed&&([selfisVertical]?[[selfcollapsibleSubview]frame].size.width<0.1:[[selfcollapsibleSubview]frame].size.height<0.1)){[selfsetCollapsibleSubviewCollapsed:YES];[selfresizeAndAdjustSubviews];}elseif([selfcollapsibleSubviewIsCollapsed]){[selfresizeAndAdjustSubviews];}[selfsetNeedsDisplay:YES];if([secondaryDelegaterespondsToSelector:@selector(splitViewDidResizeSubviews:)])[secondaryDelegatesplitViewDidResizeSubviews:aNotification];}-(void)splitViewWillResizeSubviews:(NSNotification*)aNotification{if([secondaryDelegaterespondsToSelector:@selector(splitViewWillResizeSubviews:)])[secondaryDelegatesplitViewWillResizeSubviews:aNotification];}#pragma mark - Resize Subviews Delegate Method and Helper Methods-(int)resizableSubviews{intresizableSubviews=0;for(NSView*subviewin[selfsubviews]){if([selfsubviewIsResizable:subview])resizableSubviews++;}returnresizableSubviews;}-(BOOL)subviewIsResizable:(NSView*)subview{if([selfisVertical]&&[subviewautoresizingMask]&NSViewWidthSizable)returnYES;if(![selfisVertical]&&[subviewautoresizingMask]&NSViewHeightSizable)returnYES;returnNO;}-(CGFloat)subviewMinimumSize:(int)subviewIndex;{NSNumber*minNum=[minValuesobjectForKey:[NSNumbernumberWithInt:subviewIndex]];if(!minNum)return0;intunits=0;NSNumber*unitsNum=[minUnitsobjectForKey:[NSNumbernumberWithInt:subviewIndex]];if(unitsNum)units=[unitsNumintValue];CGFloatmin=[minNumfloatValue];switch(units){case1:{// PercentCGFloatdividerThicknessTotal=[selfdividerThickness]*([[selfsubviews]count]-1);CGFloattotalSize=[selfisVertical]?[selfframe].size.width:[selfframe].size.height;totalSize-=dividerThicknessTotal;returnroundf((min/100.0)*totalSize);break;}case0:default:{// Pointsreturnmin;break;}}}-(CGFloat)subviewMaximumSize:(int)subviewIndex;{NSNumber*maxNum=[maxValuesobjectForKey:[NSNumbernumberWithInt:subviewIndex]];if(!maxNum)returnFLT_MAX;intunits=0;NSNumber*unitsNum=[maxUnitsobjectForKey:[NSNumbernumberWithInt:subviewIndex]];if(unitsNum)units=[unitsNumintValue];CGFloatmax=[maxNumfloatValue];switch(units){case1:{// PercentCGFloatdividerThicknessTotal=[selfdividerThickness]*([[selfsubviews]count]-1);CGFloattotalSize=[selfisVertical]?[selfframe].size.width:[selfframe].size.height;totalSize-=dividerThicknessTotal;returnroundf((max/100.0)*totalSize);break;}case0:default:{// Pointsreturnmax;break;}}}// PREFERRED PROPORTIONS AND SIZES//// Preferred proportions (for resizable)// Need to store resizable subviews preferred proportions for calculating new sizes//// Preferred sizes (for non-resizable)// If a non-resizable subview is ever forced larger or smaller than it prefers, we need to know it's preferred size//// Need to recalculate both of the above whenever a divider is moved, or a subview is added/removed or changed between resizable/non-resizable-(void)recalculatePreferredProportionsAndSizes;{NSMutableArray*stateArray=[NSMutableArrayarrayWithCapacity:[[selfsubviews]count]];NSMutableDictionary*preferredProportions=[NSMutableDictionarydictionary];NSMutableDictionary*preferredSizes=[NSMutableDictionarydictionary];// Total is only the sum of resizable subviewsCGFloatresizableTotal=0;// Calculate resizable totalfor(NSView*subviewin[selfsubviews]){if([selfsubviewIsResizable:subview])resizableTotal+=[selfisVertical]?[subviewframe].size.width:[subviewframe].size.height;}// Calculate resizable preferred propotions and set non-resizable preferred sizesfor(NSView*subviewin[selfsubviews]){intindex=[[selfsubviews]indexOfObject:subview];if([selfsubviewIsResizable:subview]){CGFloatsize=[selfisVertical]?[subviewframe].size.width:[subviewframe].size.height;CGFloatproportion=(resizableTotal>0)?(size/resizableTotal):0;[preferredProportionssetObject:[NSNumbernumberWithFloat:proportion]forKey:[NSNumbernumberWithInt:index]];[stateArrayaddObject:[NSNumbernumberWithBool:YES]];}else{CGFloatsize=[selfisVertical]?[subviewframe].size.width:[subviewframe].size.height;[preferredSizessetObject:[NSNumbernumberWithFloat:size]forKey:[NSNumbernumberWithInt:index]];[stateArrayaddObject:[NSNumbernumberWithBool:NO]];}}[selfsetResizableSubviewPreferredProportion:preferredProportions];[selfsetNonresizableSubviewPreferredSize:preferredSizes];if(RESIZE_DEBUG_LOGS)NSLog(@"resizableSubviewPreferredProportion: %@",resizableSubviewPreferredProportion);if(RESIZE_DEBUG_LOGS)NSLog(@"nonresizableSubviewPreferredSize: %@",nonresizableSubviewPreferredSize);// Remember state to know when to recalculate [selfsetStateForLastPreferredCalculations:stateArray];if(RESIZE_DEBUG_LOGS)NSLog(@"stateForLastPreferredCalculations: %@",stateForLastPreferredCalculations);}// Checks if the number or type of subviews has changed since we last recalculated-(BOOL)validatePreferredProportionsAndSizes;{if(RESIZE_DEBUG_LOGS)NSLog(@"validating preferred proportions and sizes");// Check if we even have saved proportions and sizesif(![selfresizableSubviewPreferredProportion]||![selfnonresizableSubviewPreferredSize])returnNO;// Check if number of items has changedif([[selfsubviews]count]!=[[selfstateForLastPreferredCalculations]count])returnNO;// Check if any of the subviews have changed between resizable and non-resizablefor(NSView*subviewin[selfsubviews]){intindex=[[selfsubviews]indexOfObject:subview];if([selfsubviewIsResizable:subview]!=[[[selfstateForLastPreferredCalculations]objectAtIndex:index]boolValue])returnNO;}returnYES;}-(void)correctCollapsiblePreferredProportionOrSize;{// TODO: Assuming that the collapsible subview does not change between resizable and non-resizable while collapsedif(![selfhasCollapsibleSubview])return;NSMutableDictionary*preferredProportions=[[[selfresizableSubviewPreferredProportion]mutableCopy]autorelease];NSMutableDictionary*preferredSizes=[[[selfnonresizableSubviewPreferredSize]mutableCopy]autorelease];NSNumber*key=[NSNumbernumberWithInt:[selfcollapsibleSubviewIndex]];NSView*subview=[selfcollapsibleSubview];// If the collapsible subview is collapsed, we put aside its preferred propotion/sizeif([selfsubviewIsCollapsed:subview]){BOOLresizable=[selfsubviewIsResizable:subview];if(!resizable){NSNumber*sizeNum=[preferredSizesobjectForKey:key];if(sizeNum){if(RESIZE_DEBUG_LOGS)NSLog(@"removing collapsible view from preferred sizes");// TODO: Save the size for later// Remove from preferred sizes[preferredSizesremoveObjectForKey:key];}}else{NSNumber*proportionNum=[preferredProportionsobjectForKey:key];if(proportionNum){if(RESIZE_DEBUG_LOGS)NSLog(@"removing collapsible view from preferred proportions");CGFloatproportion=[proportionNumfloatValue];// TODO: Save the proportion for later// Remove from preferred proportions[preferredProportionsremoveObjectForKey:key];// Recalculate other proportionsCGFloatproportionTotal=1.0-proportion;if(proportionTotal>0){for(NSNumber*pkeyin[preferredProportionsallKeys]){CGFloatoldProportion=[[preferredProportionsobjectForKey:pkey]floatValue];CGFloatnewPropotion=oldProportion/proportionTotal;[preferredProportionssetObject:[NSNumbernumberWithFloat:newPropotion]forKey:pkey];}}}}[selfsetResizableSubviewPreferredProportion:preferredProportions];[selfsetNonresizableSubviewPreferredSize:preferredSizes];}else// Otherwise, we reintegrate its preferred proportion/size{[selfclearPreferredProportionsAndSizes];[selfrecalculatePreferredProportionsAndSizes];}}-(void)validateAndCalculatePreferredProportionsAndSizes;{if(![selfvalidatePreferredProportionsAndSizes])[selfrecalculatePreferredProportionsAndSizes];// Need to make sure the collapsed subviews preferred size/proportion is in the right place[selfcorrectCollapsiblePreferredProportionOrSize];}-(void)clearPreferredProportionsAndSizes;{if(RESIZE_DEBUG_LOGS)NSLog(@"clearing preferred proportions and sizes");[selfsetResizableSubviewPreferredProportion:nil];[selfsetNonresizableSubviewPreferredSize:nil];}-(void)saveUncollapsedSizes;{[uncollapsedSizesremoveAllObjects];for(NSView*subviewin[[selfcollapsibleSubview]subviews]){NSSizeframeSize=[subviewframe].size;if([selfisVertical]){[uncollapsedSizesaddObject:[NSArrayarrayWithObjects:[NSNumbernumberWithFloat:frameSize.width],subview,nil]];}else{[uncollapsedSizesaddObject:[NSArrayarrayWithObjects:[NSNumbernumberWithFloat:frameSize.height],subview,nil]];}}}-(void)restoreUncollapsedSizes{floatconstantWidth=[selfcollapsibleSubview].frame.size.width;floatconstantHeight=[selfcollapsibleSubview].frame.size.height;for(NSArray*uncollapsedSizeStateinuncollapsedSizes){CGFloatsize=[[uncollapsedSizeStateobjectAtIndex:0]floatValue];NSView*view=[uncollapsedSizeStateobjectAtIndex:1];if([selfisVertical]){[viewsetFrameSize:NSMakeSize(size,constantHeight)];}else{[viewsetFrameSize:NSMakeSize(constantWidth,size)];}}[uncollapsedSizesremoveAllObjects];}// RESIZING ALGORITHM// non-resizable subviews are given preferred size// overall remaining size is calculated// resizable subviews are calculated based on remaining size and preferred proportions// resizable subviews are checked for min/max constraint violations// if violating constraint, set to valid size and remove from resizable subviews// recalculate other resizable subviews and repeat// if all resizable subviews reached constraints without meeting target size, need to resize non-resizable views// non-resizable subviews are adjusted proportionally to meet target size// non-resizable subviews are checked for min/max constraint violations// if violating constraint, set to valid size and remove from non-resizable subviews// recalculate other non-resizable subviews and repeat// if all subviews reached constraints without meeting target size, need to adjust all views to fit// proportionally resize all subviews to fit in target size, ignoring min/max constraints-(void)resizeAndAdjustSubviews;{// Temporary: for now, we will just remember the proportions the first time subviews are resized// we should be remember them in the user defaults so they save across quits (TODO)[selfvalidateAndCalculatePreferredProportionsAndSizes];if(RESIZE_DEBUG_LOGS)NSLog(@"resizeSubviews begins -----------------------------------------------------");NSMutableDictionary*newSubviewSizes=[NSMutableDictionarydictionaryWithCapacity:[[selfsubviews]count]];// Get new total sizeCGFloattotalAvailableSize=[selfisVertical]?[selfframe].size.width:[selfframe].size.height;if(RESIZE_DEBUG_LOGS)NSLog(@"totalAvailableSize: %f",totalAvailableSize);// Calculate non-resizable subviews totalCGFloatnonresizableSubviewsTotalPreferredSize=0;for(NSNumber*sizein[nonresizableSubviewPreferredSizeallValues])nonresizableSubviewsTotalPreferredSize+=[sizefloatValue];if(RESIZE_DEBUG_LOGS)NSLog(@"nonresizableSubviewsTotalPreferredSize: %f",nonresizableSubviewsTotalPreferredSize);// Calculate divider thickness totalintdividerCount=[[selfsubviews]count]-1;if([selfcollapsibleSubviewIsCollapsed]&&dividerCanCollapse)dividerCount--;CGFloatdividerThicknessTotal=[selfdividerThickness]*dividerCount;if(RESIZE_DEBUG_LOGS)NSLog(@"dividerThicknessTotal: %f",dividerThicknessTotal);// Calculate overall remaining size (could be negative)CGFloatresizableSubviewsTotalAvailableSize=totalAvailableSize-nonresizableSubviewsTotalPreferredSize-dividerThicknessTotal;if(RESIZE_DEBUG_LOGS)NSLog(@"resizableSubviewsTotalAvailableSize: %f",resizableSubviewsTotalAvailableSize);// Special case for the collapsible subviewif([selfcollapsibleSubviewIsCollapsed]){[newSubviewSizessetObject:[NSNumbernumberWithFloat:0.0]forKey:[NSNumbernumberWithInt:[selfcollapsibleSubviewIndex]]];}// Set non-resizable subviews to preferred size[newSubviewSizesaddEntriesFromDictionary:nonresizableSubviewPreferredSize];// Set sizes of resizable views based on proportions (could be negative)CGFloatresizableSubviewAvailableSizeUsed=0;intresizableSubviewCounter=0;intresizableSubviewCount=[resizableSubviewPreferredProportioncount];for(NSNumber*keyin[resizableSubviewPreferredProportionallKeys]){resizableSubviewCounter++;CGFloatproportion=[[resizableSubviewPreferredProportionobjectForKey:key]floatValue];CGFloatsize=roundf(proportion*resizableSubviewsTotalAvailableSize);resizableSubviewAvailableSizeUsed+=size;if(resizableSubviewCounter==resizableSubviewCount){// Make adjustment if necessarysize+=(resizableSubviewsTotalAvailableSize-resizableSubviewAvailableSizeUsed);}[newSubviewSizessetObject:[NSNumbernumberWithFloat:size]forKey:key];}if(RESIZE_DEBUG_LOGS)NSLog(@"newSubviewSizes after resizable proportional resizing: %@",newSubviewSizes);// TODO: Could add a special case for resizableSubviewsTotalAvailableSize <= 0 : just set all resizable subviews to minimum size // Make array of all the resizable subviews indexesNSMutableArray*resizableSubviewIndexes=[[[resizableSubviewPreferredProportionallKeys]mutableCopy]autorelease];[resizableSubviewIndexessortUsingDescriptors:[NSArrayarrayWithObject:[[[NSSortDescriptoralloc]initWithKey:@"self"ascending:YES]autorelease]]];// Loop until none of the resizable subviews' constraints are violatedCGFloatproportionTotal=1;CGFloatresizableSubviewsRemainingAvailableSize=resizableSubviewsTotalAvailableSize;inti;for(i=0;i<[resizableSubviewIndexescount];i++){NSNumber*key=[resizableSubviewIndexesobjectAtIndex:i];CGFloatsize=[[newSubviewSizesobjectForKey:key]floatValue];CGFloatminSize=[selfsubviewMinimumSize:[keyintValue]];CGFloatmaxSize=[selfsubviewMaximumSize:[keyintValue]];BOOLoverMax=size>maxSize;BOOLunderMin=size<minSize;// Check if current item in array violates constraintsif(underMin||overMax){CGFloatconstrainedSize=underMin?minSize:maxSize;if(RESIZE_DEBUG_LOGS)NSLog(@"resizable subview %@ was %@, set to %f",key,(underMin?@"under min":@"over max"),constrainedSize);// Give subview constrained size and remove from array[newSubviewSizessetObject:[NSNumbernumberWithFloat:constrainedSize]forKey:key];[resizableSubviewIndexesremoveObject:key];// Adjust total proportion and remaining available sizeproportionTotal-=[[resizableSubviewPreferredProportionobjectForKey:key]floatValue];resizableSubviewsRemainingAvailableSize-=underMin?minSize:maxSize;// Recalculate remaining subview sizesCGFloatresizableSubviewRemainingSizeUsed=0;intj;for(j=0;j<[resizableSubviewIndexescount];j++){NSNumber*jKey=[resizableSubviewIndexesobjectAtIndex:j];CGFloatproportion=0;if(proportionTotal>0)proportion=[[resizableSubviewPreferredProportionobjectForKey:jKey]floatValue]/proportionTotal;elseproportion=1.0/[resizableSubviewIndexescount];CGFloatsize=roundf(proportion*resizableSubviewsRemainingAvailableSize);resizableSubviewRemainingSizeUsed+=size;if(j==[resizableSubviewIndexescount]-1){// Make adjustment if necessarysize+=(resizableSubviewsRemainingAvailableSize-resizableSubviewRemainingSizeUsed);}[newSubviewSizessetObject:[NSNumbernumberWithFloat:size]forKey:jKey];// Reset outer loop to start from beginningi=-1;}}}if(RESIZE_DEBUG_LOGS)NSLog(@"newSubviewSizes after resizable constraint fulfilling: %@",newSubviewSizes);if([resizableSubviewIndexescount]==0&&resizableSubviewsRemainingAvailableSize!=0){if(RESIZE_DEBUG_LOGS)NSLog(@"entering nonresizable adjustment stage");// All resizable subviews have reached constraints without reaching the target size// First try to adjust non-resizable subviews, with resizableSubviewsRemainingAvailableSize being the amount of adjustment needed// Make array of non-resizable preferred proportions (normally go by preferred sizes)NSMutableDictionary*nonresizableSubviewPreferredProportion=[NSMutableDictionarydictionary];for(NSNumber*keyin[nonresizableSubviewPreferredSizeallKeys]){CGFloatproportion=[[nonresizableSubviewPreferredSizeobjectForKey:key]floatValue]/nonresizableSubviewsTotalPreferredSize;[nonresizableSubviewPreferredProportionsetObject:[NSNumbernumberWithFloat:proportion]forKey:key];}// ResizableSubviewsRemainingAvailableSize is the amount of adjustment neededCGFloatnonresizableSubviewsRemainingAvailableSize=nonresizableSubviewsTotalPreferredSize+resizableSubviewsRemainingAvailableSize;// Set sizes of nonresizable views based on proportions (could be negative)CGFloatnonresizableSubviewAvailableSizeUsed=0;intnonresizableSubviewCounter=0;intnonresizableSubviewCount=[nonresizableSubviewPreferredProportioncount];for(NSNumber*keyin[nonresizableSubviewPreferredProportionallKeys]){nonresizableSubviewCounter++;CGFloatproportion=[[nonresizableSubviewPreferredProportionobjectForKey:key]floatValue];CGFloatsize=roundf(proportion*nonresizableSubviewsRemainingAvailableSize);nonresizableSubviewAvailableSizeUsed+=size;if(nonresizableSubviewCounter==nonresizableSubviewCount){// Make adjustment if necessarysize+=(nonresizableSubviewsRemainingAvailableSize-nonresizableSubviewAvailableSizeUsed);}[newSubviewSizessetObject:[NSNumbernumberWithFloat:size]forKey:key];}if(RESIZE_DEBUG_LOGS)NSLog(@"newSubviewSizes after nonresizable proportional resizing: %@",newSubviewSizes);// Make array of all the non-resizable subviews indexesNSMutableArray*nonresizableSubviewIndexes=[[[nonresizableSubviewPreferredSizeallKeys]mutableCopy]autorelease];[nonresizableSubviewIndexessortUsingDescriptors:[NSArrayarrayWithObject:[[[NSSortDescriptoralloc]initWithKey:@"self"ascending:YES]autorelease]]];// Loop until none of the non-resizable subviews' constraints are violatedCGFloatproportionTotal=1;inti;for(i=0;i<[nonresizableSubviewIndexescount];i++){NSNumber*key=[nonresizableSubviewIndexesobjectAtIndex:i];CGFloatsize=[[newSubviewSizesobjectForKey:key]floatValue];CGFloatminSize=[selfsubviewMinimumSize:[keyintValue]];CGFloatmaxSize=[selfsubviewMaximumSize:[keyintValue]];BOOLoverMax=size>maxSize;BOOLunderMin=size<minSize;// Check if current item in array violates constraintsif(underMin||overMax){CGFloatconstrainedSize=underMin?minSize:maxSize;if(RESIZE_DEBUG_LOGS)NSLog(@"nonresizable subview %@ was %@, set to %f",key,(underMin?@"under min":@"over max"),constrainedSize);// Give subview constrained size and remove from array[newSubviewSizessetObject:[NSNumbernumberWithFloat:constrainedSize]forKey:key];[nonresizableSubviewIndexesremoveObject:key];// Adjust total proportion and remaining available sizeproportionTotal-=[[nonresizableSubviewPreferredProportionobjectForKey:key]floatValue];nonresizableSubviewsRemainingAvailableSize-=underMin?minSize:maxSize;// Recalculate remaining subview sizesCGFloatnonresizableSubviewRemainingSizeUsed=0;intj;for(j=0;j<[nonresizableSubviewIndexescount];j++){NSNumber*jKey=[nonresizableSubviewIndexesobjectAtIndex:j];CGFloatproportion=0;if(proportionTotal>0)proportion=[[nonresizableSubviewPreferredProportionobjectForKey:jKey]floatValue]/proportionTotal;elseproportion=1.0/[nonresizableSubviewIndexescount];CGFloatsize=roundf(proportion*nonresizableSubviewsRemainingAvailableSize);nonresizableSubviewRemainingSizeUsed+=size;if(j==[nonresizableSubviewIndexescount]-1){// Make adjustment if necessarysize+=(nonresizableSubviewsRemainingAvailableSize-nonresizableSubviewRemainingSizeUsed);}[newSubviewSizessetObject:[NSNumbernumberWithFloat:size]forKey:jKey];// Reset outer loop to start from beginningi=-1;}}}if(RESIZE_DEBUG_LOGS)NSLog(@"newSubviewSizes after nonresizable constraint fulfilling: %@",newSubviewSizes);// If there is still overall violation, resize everything proportionally to make up the differenceif([resizableSubviewIndexescount]==0&&nonresizableSubviewsRemainingAvailableSize!=0){if(RESIZE_DEBUG_LOGS)NSLog(@"entering all subviews forced adjustment stage");// Calculate current proportions and use to calculate new sizeCGFloatallSubviewTotalCurrentSize=0;for(NSNumber*sizein[newSubviewSizesallValues])allSubviewTotalCurrentSize+=[sizefloatValue];CGFloatallSubviewRemainingSizeUsed=0;CGFloatallSubviewTotalSize=totalAvailableSize-dividerThicknessTotal;// TODO: What to do if even the dividers don't fit? intk;for(k=0;k<[newSubviewSizescount];k++){NSNumber*key=[NSNumbernumberWithInt:k];CGFloatcurrentSize=[[newSubviewSizesobjectForKey:key]floatValue];CGFloatproportion=currentSize/allSubviewTotalCurrentSize;CGFloatsize=roundf(proportion*allSubviewTotalSize);allSubviewRemainingSizeUsed+=size;if(k==[newSubviewSizescount]-1){// Make adjustment if necessarysize+=allSubviewTotalSize-allSubviewRemainingSizeUsed;}[newSubviewSizessetObject:[NSNumbernumberWithFloat:size]forKey:key];}if(RESIZE_DEBUG_LOGS)NSLog(@"newSubviewSizes after all subviews forced adjustment: %@",newSubviewSizes);}// Otherwise there is still flexibiliy in the non-resizable views, so we are done}// Otherwise there is still flexibility in the resizable views, so we are done// Set subview framesCGFloatposition=0;for(i=0;i<[[selfsubviews]count];i++){NSView*subview=[[selfsubviews]objectAtIndex:i];CGFloatsize=[[newSubviewSizesobjectForKey:[NSNumbernumberWithInt:i]]floatValue];NSRectsubviewFrame=NSZeroRect;if([selfisVertical]){subviewFrame.size.height=[selfframe].size.height;subviewFrame.size.width=size;subviewFrame.origin.y=[subviewframe].origin.y;subviewFrame.origin.x=position;}else{subviewFrame.size.height=size;subviewFrame.size.width=[selfframe].size.width;subviewFrame.origin.y=position;subviewFrame.origin.x=[subviewframe].origin.x;}[subviewsetFrame:subviewFrame];position+=size;if(dividerCanCollapse&&[selfsubviewIsCollapsed:subview]){// Do nothing}else{position+=[selfdividerThickness];}}}-(void)splitView:(NSSplitView*)senderresizeSubviewsWithOldSize:(NSSize)oldSize{if([secondaryDelegateisKindOfClass:[BWAnchoredButtonBarclass]]){[selfresizeAndAdjustSubviews];}elseif([secondaryDelegaterespondsToSelector:@selector(splitView:resizeSubviewsWithOldSize:)]){[secondaryDelegatesplitView:senderresizeSubviewsWithOldSize:oldSize];}elseif(sender==self){[selfresizeAndAdjustSubviews];}else{[senderadjustSubviews];}}-(void)setDividerStyle:(NSSplitViewDividerStyle)aStyle{[supersetDividerStyle:aStyle];// There can be sizing issues during design-time if we don't call this[selfadjustSubviews];}#pragma mark IB Inspector Support Methods-(BOOL)checkboxIsEnabled{if(![selfisVertical]&&[superdividerThickness]>1.01)returnNO;returnYES;}-(void)setColorIsEnabled:(BOOL)flag{colorIsEnabled=flag;[selfsetNeedsDisplay:YES];}-(void)setColor:(NSColor*)aColor{if(color!=aColor){[colorrelease];color=[aColorcopy];}[selfsetNeedsDisplay:YES];}-(NSColor*)color{if(color==nil)color=[[NSColorblackColor]retain];return[[colorretain]autorelease];}-(NSMutableDictionary*)minValues{if(minValues==nil)minValues=[NSMutableDictionarynew];return[[minValuesretain]autorelease];}-(NSMutableDictionary*)maxValues{if(maxValues==nil)maxValues=[NSMutableDictionarynew];return[[maxValuesretain]autorelease];}-(NSMutableDictionary*)minUnits{if(minUnits==nil)minUnits=[NSMutableDictionarynew];return[[minUnitsretain]autorelease];}-(NSMutableDictionary*)maxUnits{if(maxUnits==nil)maxUnits=[NSMutableDictionarynew];return[[maxUnitsretain]autorelease];}-(void)dealloc{[uncollapsedSizesrelease];[colorrelease];[minValuesrelease];[maxValuesrelease];[minUnitsrelease];[maxUnitsrelease];[resizableSubviewPreferredProportionrelease];[nonresizableSubviewPreferredSizerelease];[toggleCollapseButtonrelease];[stateForLastPreferredCalculationsrelease];[superdealloc];}@end