| File: | Frameworks/RBSplitView/Source/RBSplitSubview.m |
| Location: | line 687, column 10 |
| Description: | dead initialization |
| 1 | // |
| 2 | // RBSplitSubview.m version 1.1.4 |
| 3 | // RBSplitView |
| 4 | // |
| 5 | // Created by Rainer Brockerhoff on 19/11/2004. |
| 6 | // Copyright 2004-2006 Rainer Brockerhoff. |
| 7 | // Some Rights Reserved under the Creative Commons Attribution License, version 2.5, and/or the MIT License. |
| 8 | // |
| 9 | |
| 10 | #import "RBSplitView.h" |
| 11 | #import "RBSplitViewPrivateDefines.h" |
| 12 | |
| 13 | // This variable points to the animation data structure while an animation is in |
| 14 | // progress; if there's none, it will be NULL. Animating may be very CPU-intensive so |
| 15 | // we allow only one animation to take place at a time. |
| 16 | static animationData* currentAnimation = NULL( ( void * ) 0 ); |
| 17 | |
| 18 | @implementation RBSplitSubview |
| 19 | |
| 20 | // This class method returns YES if an animation is in progress. |
| 21 | + (BOOL)animating { |
| 22 | return currentAnimation!=NULL( ( void * ) 0 ); |
| 23 | } |
| 24 | |
| 25 | // This is the designated initializer for RBSplitSubview. It sets some reasonable defaults. However, you |
| 26 | // can't rely on anything working until you insert it into a RBSplitView. |
| 27 | - (id)initWithFrame:(NSRect)frame { |
| 28 | self = [super initWithFrame:frame]; |
| 29 | if (self) { |
| 30 | fraction = 0.0; |
| 31 | canCollapse = NO( BOOL ) 0; |
| 32 | notInLimits = NO( BOOL ) 0; |
| 33 | minDimension = 1.0; |
| 34 | maxDimension = WAYOUT( 1000000.0 ); |
| 35 | identifier = @""; |
| 36 | previous = NSZeroRect; |
| 37 | savedSize = frame.size; |
| 38 | actDivider = NSNotFound; |
| 39 | canDragWindow = NO( BOOL ) 0; |
| 40 | } |
| 41 | return self; |
| 42 | } |
| 43 | |
| 44 | // Just releases our stuff when going away. |
| 45 | - (void)dealloc { |
| 46 | [identifier release]; |
| 47 | [super dealloc]; |
| 48 | } |
| 49 | |
| 50 | // These return nil since we're not a RBSplitView (they're overridden there). |
| 51 | - (RBSplitView*)asSplitView { |
| 52 | return nil0; |
| 53 | } |
| 54 | |
| 55 | - (RBSplitView*)coupledSplitView { |
| 56 | return nil0; |
| 57 | } |
| 58 | |
| 59 | // Sets and gets the coupling between a RBSplitView and its containing RBSplitView (if any). |
| 60 | // For convenience, these methods are also implemented here. |
| 61 | - (void)setCoupled:(BOOL)flag { |
| 62 | } |
| 63 | |
| 64 | - (BOOL)isCoupled { |
| 65 | return NO( BOOL ) 0; |
| 66 | } |
| 67 | |
| 68 | // RBSplitSubviews are never flipped, unless they're RBSplitViews. |
| 69 | - (BOOL)isFlipped { |
| 70 | return NO( BOOL ) 0; |
| 71 | } |
| 72 | |
| 73 | // We copy the opacity of the owning split view. |
| 74 | - (BOOL)isOpaque { |
| 75 | return [[self couplingSplitView] isOpaque]; |
| 76 | } |
| 77 | |
| 78 | // A hidden RBSplitSubview is not redrawn and is not considered for drawing dividers. |
| 79 | // This won't work before 10.3, though. |
| 80 | - (void)setHidden:(BOOL)flag { |
| 81 | if ([self isHidden]!=flag) { |
| 82 | RBSplitView* sv = [self splitView]; |
| 83 | [self RB___setHidden:flag]; |
| 84 | if (flag) { |
| 85 | [sv adjustSubviews]; |
| 86 | } else { |
| 87 | [sv adjustSubviewsExcepting:self]; |
| 88 | } |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | // RBSplitSubviews can't be in the responder chain. |
| 93 | - (BOOL)acceptsFirstResponder { |
| 94 | return NO( BOOL ) 0; |
| 95 | } |
| 96 | |
| 97 | // Mousing down should move the window only for a completely transparent background. This might have |
| 98 | // unintended side effects in metal windows, so for those you might want to use a background color |
| 99 | // with a very low alpha (0.01 for instance). |
| 100 | // This is commented out as I'm still experimenting with it. |
| 101 | /*- (BOOL)mouseDownCanMoveWindow { |
| 102 | RBSplitView* sv = [self asSplitView]; |
| 103 | if (!sv) { |
| 104 | sv = [self couplingSplitView]; |
| 105 | } |
| 106 | return [sv background]==nil; |
| 107 | return YES; |
| 108 | }*/ |
| 109 | |
| 110 | // This returns the owning splitview. It's guaranteed to return a RBSplitView or nil. |
| 111 | // You should avoid having "orphan" RBSplitSubviews, or at least manipulating |
| 112 | // them while they're not inserted in a RBSplitView. |
| 113 | - (RBSplitView*)splitView { |
| 114 | id result = [self superview]; |
| 115 | if ([result isKindOfClass:[RBSplitView class]]) { |
| 116 | return (RBSplitView*)result; |
| 117 | } |
| 118 | return nil0; |
| 119 | } |
| 120 | |
| 121 | // This also returns the owning splitview. It's overridden for nested RBSplitViews. |
| 122 | - (RBSplitView*)couplingSplitView { |
| 123 | id result = [self superview]; |
| 124 | if ([result isKindOfClass:[RBSplitView class]]) { |
| 125 | return (RBSplitView*)result; |
| 126 | } |
| 127 | return nil0; |
| 128 | } |
| 129 | |
| 130 | // This returns the outermost directly containing RBSplitView, or nil. |
| 131 | - (RBSplitView*)outermostSplitView { |
| 132 | id result = nil0; |
| 133 | id sv = self; |
| 134 | while ((sv = [sv superview])&&[sv isKindOfClass:[RBSplitView class]]) { |
| 135 | result = sv; |
| 136 | } |
| 137 | return result; |
| 138 | } |
| 139 | |
| 140 | // This convenience method returns YES if the containing RBSplitView is horizontal. |
| 141 | - (BOOL)splitViewIsHorizontal { |
| 142 | return [[self splitView] isHorizontal]; |
| 143 | } |
| 144 | |
| 145 | // You can use either tags (ints) or identifiers (NSStrings) to identify individual subviews. |
| 146 | // We take care not to have nil identifiers. |
| 147 | - (void)setTag:(int)theTag { |
| 148 | tag = theTag; |
| 149 | } |
| 150 | |
| 151 | - (int)tag { |
| 152 | return tag; |
| 153 | } |
| 154 | |
| 155 | - (void)setIdentifier:(NSString*)aString { |
| 156 | [identifier autorelease]; |
| 157 | identifier = aString?[aString retain]:@""; |
| 158 | } |
| 159 | |
| 160 | - (NSString*)identifier { |
| 161 | return identifier; |
| 162 | } |
| 163 | |
| 164 | // If we have an identifier, this will make debugging a little easier by appending it to the |
| 165 | // default description. |
| 166 | - (NSString*)description { |
| 167 | return [identifier length]>0?[NSString stringWithFormat:@"%@(%@)",[super description],identifier]:[super description]; |
| 168 | } |
| 169 | |
| 170 | // This pair of methods allows you to get and change the position of a subview (within the split view); |
| 171 | // this counts from zero from the left or top of the split view. |
| 172 | - (unsigned)position { |
| 173 | RBSplitView* sv = [self splitView]; |
| 174 | return sv?[[sv subviews] indexOfObjectIdenticalTo:self]:0; |
| 175 | } |
| 176 | |
| 177 | - (void)setPosition:(unsigned)newPosition { |
| 178 | RBSplitView* sv = [self splitView]; |
| 179 | if (sv) { |
| 180 | [self retain]; |
| 181 | [self removeFromSuperviewWithoutNeedingDisplay]; |
| 182 | NSArray* subviews = [sv subviews]; |
| 183 | if (newPosition>=[subviews count]) { |
| 184 | [sv addSubview:self positioned:NSWindowAbove relativeTo:nil0]; |
| 185 | } else { |
| 186 | [sv addSubview:self positioned:NSWindowBelow relativeTo:[subviews objectAtIndex:newPosition]]; |
| 187 | } |
| 188 | [self release]; |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | // Tests whether the subview is collapsed. |
| 193 | - (BOOL)isCollapsed { |
| 194 | return [self RB___visibleDimension]<=0.0; |
| 195 | } |
| 196 | |
| 197 | // Tests whether the subview can shrink further. |
| 198 | - (BOOL)canShrink { |
| 199 | return [self RB___visibleDimension]>([self canCollapse]?0.0:minDimension); |
| 200 | } |
| 201 | |
| 202 | // Tests whether the subview can expand further. |
| 203 | - (BOOL)canExpand { |
| 204 | return [self RB___visibleDimension]<maxDimension; |
| 205 | } |
| 206 | |
| 207 | // Returns the subview's status. |
| 208 | - (RBSSubviewStatus)status { |
| 209 | animationData* anim = [self RB___animationData:NO( BOOL ) 0 resize:NO( BOOL ) 0]; |
| 210 | if (anim) { |
| 211 | return anim->collapsing?RBSSubviewCollapsing:RBSSubviewExpanding; |
| 212 | } |
| 213 | return [self RB___visibleDimension]<=0.0?RBSSubviewCollapsed:RBSSubviewNormal; |
| 214 | } |
| 215 | |
| 216 | // Tests whether the subview can be collapsed. The local instance variable will be overridden by the |
| 217 | // delegate method if it's implemented. |
| 218 | - (BOOL)canCollapse { |
| 219 | BOOL result = canCollapse; |
| 220 | RBSplitView* sv = [self splitView]; |
| 221 | if ([sv RB___numberOfSubviews]<2) { |
| 222 | return NO( BOOL ) 0; |
| 223 | } |
| 224 | id delegate = [sv delegate]; |
| 225 | if ([delegate respondsToSelector:@selector(splitView:canCollapse:)]) { |
| 226 | result = [delegate splitView:sv canCollapse:self]; |
| 227 | } |
| 228 | return result; |
| 229 | } |
| 230 | |
| 231 | // This sets the subview's "canCollapse" flag. Ignored if the delegate's splitView:canCollapse: |
| 232 | // method is implemented. |
| 233 | - (void)setCanCollapse:(BOOL)flag { |
| 234 | canCollapse = flag; |
| 235 | } |
| 236 | |
| 237 | // This expands a collapsed subview and calls the delegate's splitView:didExpand: method, if it exists. |
| 238 | // This is not called internally by other methods; call this to expand a subview programmatically. |
| 239 | // As a convenience to other methods, it returns the subview's dimension after expanding (this may be |
| 240 | // off by 1 pixel due to rounding) or 0.0 if it couldn't be expanded. |
| 241 | // The delegate should not change the subview's frame. |
| 242 | - (float)expand { |
| 243 | return [self RB___expandAndSetToMinimum:NO( BOOL ) 0]; |
| 244 | } |
| 245 | |
| 246 | // This collapses an expanded subview and calls the delegate's splitView:didCollapse: method, if it exists. |
| 247 | // This is not called internally by other methods; call this to expand a subview programmatically. |
| 248 | // As a convenience to other methods, it returns the negative of the subview's dimension before |
| 249 | // collapsing (or 0.0 if it couldn't be collapsed). |
| 250 | // The delegate should not change the subview's frame. |
| 251 | - (float)collapse { |
| 252 | return [self RB___collapse]; |
| 253 | } |
| 254 | |
| 255 | // This tries to collapse the subview with animation, and collapses it instantly if some other |
| 256 | // subview is animating. Returns YES if animation was started successfully. |
| 257 | - (BOOL)collapseWithAnimation { |
| 258 | return [self collapseWithAnimation:YES( BOOL ) 1 withResize:YES( BOOL ) 1]; |
| 259 | } |
| 260 | |
| 261 | // This tries to expand the subview with animation, and expands it instantly if some other |
| 262 | // subview is animating. Returns YES if animation was started successfully. |
| 263 | - (BOOL)expandWithAnimation { |
| 264 | return [self expandWithAnimation:YES( BOOL ) 1 withResize:YES( BOOL ) 1]; |
| 265 | } |
| 266 | |
| 267 | // These methods collapse and expand subviews with animation, depending on the parameters. |
| 268 | // They return YES if animation startup was successful. If resize is NO, the subview is |
| 269 | // collapsed/expanded without resizing it during animation. |
| 270 | - (BOOL)collapseWithAnimation:(BOOL)animate withResize:(BOOL)resize { |
| 271 | if ([self status]==RBSSubviewNormal) { |
| 272 | if ([self canCollapse]) { |
| 273 | if (animate&&[self RB___animationData:YES( BOOL ) 1 resize:resize]) { |
| 274 | [self RB___clearResponder]; |
| 275 | [self RB___stepAnimation]; |
| 276 | return YES( BOOL ) 1; |
| 277 | } else { |
| 278 | [self RB___collapse]; |
| 279 | } |
| 280 | } |
| 281 | } |
| 282 | return NO( BOOL ) 0; |
| 283 | } |
| 284 | |
| 285 | - (BOOL)expandWithAnimation:(BOOL)animate withResize:(BOOL)resize { |
| 286 | if ([self status]==RBSSubviewCollapsed) { |
| 287 | if (animate&&[self RB___animationData:YES( BOOL ) 1 resize:resize]) { |
| 288 | [self RB___stepAnimation]; |
| 289 | return YES( BOOL ) 1; |
| 290 | } else { |
| 291 | [self RB___expandAndSetToMinimum:NO( BOOL ) 0]; |
| 292 | } |
| 293 | } |
| 294 | return NO( BOOL ) 0; |
| 295 | } |
| 296 | |
| 297 | |
| 298 | // These 3 methods get and set the view's minimum and maximum dimensions. |
| 299 | // The minimum dimension ought to be an integer at least equal to 1.0 but we make sure. |
| 300 | // The maximum dimension ought to be an integer at least equal to the minimum. As a convenience, |
| 301 | // pass in zero to set it to some huge number. |
| 302 | - (float)minDimension { |
| 303 | return minDimension; |
| 304 | } |
| 305 | |
| 306 | - (float)maxDimension { |
| 307 | return maxDimension; |
| 308 | } |
| 309 | |
| 310 | - (void)setMinDimension:(float)newMinDimension andMaxDimension:(float)newMaxDimension { |
| 311 | minDimension = MAX( { __typeof__ ( 1.0 ) __a = ( 1.0 ) ; __typeof__ ( floorf ( newMinDimension ) ) __b = ( floorf ( newMinDimension ) ) ; __a < __b ? __b : __a ; } )(1.0,floorf(newMinDimension)); |
| 312 | if (newMaxDimension<1.0) { |
| 313 | newMaxDimension = WAYOUT( 1000000.0 ); |
| 314 | } |
| 315 | maxDimension = MAX( { __typeof__ ( minDimension ) __a = ( minDimension ) ; __typeof__ ( floorf ( newMaxDimension ) ) __b = ( floorf ( newMaxDimension ) ) ; __a < __b ? __b : __a ; } )(minDimension,floorf(newMaxDimension)); |
| 316 | float dim = [self dimension]; |
| 317 | if ((dim<minDimension)||(dim>maxDimension)) { |
| 318 | [[self splitView] setMustAdjust]; |
| 319 | } |
| 320 | } |
| 321 | |
| 322 | // This returns the subview's dimension. If it's collapsed, it returns the dimension it would have |
| 323 | // after expanding. |
| 324 | - (float)dimension { |
| 325 | float dim = [self RB___visibleDimension]; |
| 326 | if (dim<=0.0) { |
| 327 | dim = [[self splitView] RB___dimensionWithoutDividers]*fraction; |
| 328 | if (dim<minDimension) { |
| 329 | dim = minDimension; |
| 330 | } else if (dim>maxDimension) { |
| 331 | dim = maxDimension; |
| 332 | } |
| 333 | } |
| 334 | return dim; |
| 335 | } |
| 336 | |
| 337 | // Sets the current dimension of the subview, subject to the current maximum and minimum. |
| 338 | // If the subview is collapsed, this will have an effect only after reexpanding. |
| 339 | - (void)setDimension:(float)value { |
| 340 | RBSplitView* sv = [self splitView]; |
| 341 | NSSize size = [self frame].size; |
| 342 | BOOL ishor = [sv isHorizontal]; |
| 343 | if (DIM( ( ( float * ) & ( size ) ) [ ishor ] )(size)>0.0) { |
| 344 | // We're not collapsed, set the size and adjust other subviews. |
| 345 | DIM( ( ( float * ) & ( size ) ) [ ishor ] )(size) = value; |
| 346 | [self setFrameSize:size]; |
| 347 | [sv adjustSubviewsExcepting:self]; |
| 348 | } else { |
| 349 | // We're collapsed, adjust the fraction so that we'll have the (approximately) correct |
| 350 | // dimension after expanding. |
| 351 | fraction = value/[sv RB___dimensionWithoutDividers]; |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | // This just draws the background of a subview, then tells the delegate, if any. |
| 356 | // The delegate would usually draw a frame inside the subview. |
| 357 | - (void)drawRect:(NSRect)rect { |
| 358 | RBSplitView* sv = [self splitView]; |
| 359 | NSColor* bg = [sv background]; |
| 360 | if (bg) { |
| 361 | [bg set]; |
| 362 | NSRectFillUsingOperation(rect,NSCompositeSourceOver); |
| 363 | } |
| 364 | id del = [sv delegate]; |
| 365 | if ([del respondsToSelector:@selector(splitView:willDrawSubview:inRect:)]) { |
| 366 | [del splitView:sv willDrawSubview:self inRect:rect]; |
| 367 | } |
| 368 | } |
| 369 | |
| 370 | // We check if the RBSplitView must be adjusted before redisplaying programmatically. |
| 371 | // if so, we adjust and display the whole RBSplitView. |
| 372 | - (void)display { |
| 373 | RBSplitView* sv = [self splitView]; |
| 374 | if (sv) { |
| 375 | if ([sv mustAdjust]) { |
| 376 | [sv display]; |
| 377 | } else { |
| 378 | [super display]; |
| 379 | } |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | // RBSplitSubviews will always resize their own subviews. |
| 384 | - (BOOL)autoresizesSubviews { |
| 385 | return YES( BOOL ) 1; |
| 386 | } |
| 387 | |
| 388 | // This is method is called automatically when the subview is resized; don't call it yourself. |
| 389 | - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize { |
| 390 | RBSplitView* sv = [self splitView]; |
| 391 | if (sv) { |
| 392 | BOOL ishor = [sv isHorizontal]; |
| 393 | NSRect frame = [self frame]; |
| 394 | float dim = DIM( ( ( float * ) & ( frame . size ) ) [ ishor ] )(frame.size); |
| 395 | float other = OTHER( ( ( float * ) & ( frame . size ) ) [ ! ishor ] )(frame.size); |
| 396 | // We resize subviews only when we're inside the subview's limits and the containing splitview's limits. |
| 397 | animationData* anim = [self RB___animationData:NO( BOOL ) 0 resize:NO( BOOL ) 0]; |
| 398 | if ((dim>=(anim&&!anim->resizing?anim->dimension:minDimension))&&(dim<=maxDimension)&&(other>=[sv minDimension])&&(other<=[sv maxDimension])) { |
| 399 | if (notInLimits) { |
| 400 | // The subviews can be resized, so we restore the saved size. |
| 401 | oldBoundsSize = savedSize; |
| 402 | } |
| 403 | // We save the size every time the subview's subviews are resized within the limits. |
| 404 | notInLimits = NO( BOOL ) 0; |
| 405 | savedSize = frame.size; |
| 406 | [super resizeSubviewsWithOldSize:oldBoundsSize]; |
| 407 | } else { |
| 408 | notInLimits = YES( BOOL ) 1; |
| 409 | } |
| 410 | } |
| 411 | } |
| 412 | |
| 413 | // This method is used internally when a divider is dragged. It tries to change the subview's dimension |
| 414 | // and returns the actual change, collapsing or expanding whenever possible. You usually won't need |
| 415 | // to call this directly. |
| 416 | - (float)changeDimensionBy:(float)increment mayCollapse:(BOOL)mayCollapse move:(BOOL)move { |
| 417 | RBSplitView* sv = [self splitView]; |
| 418 | if (!sv||(fabsf(increment)<1.0)) { |
| 419 | return 0.0; |
| 420 | } |
| 421 | BOOL ishor = [sv isHorizontal]; |
| 422 | NSRect frame = [self frame]; |
| 423 | float olddim = DIM( ( ( float * ) & ( frame . size ) ) [ ishor ] )(frame.size); |
| 424 | float newdim = MAX( { __typeof__ ( 0.0 ) __a = ( 0.0 ) ; __typeof__ ( olddim + increment ) __b = ( olddim + increment ) ; __a < __b ? __b : __a ; } )(0.0,olddim+increment); |
| 425 | if (newdim<olddim) { |
| 426 | if (newdim<minDimension) { |
| 427 | // Collapse if needed |
| 428 | if (mayCollapse&&[self canCollapse]&&(newdim<MAX( { __typeof__ ( 1.0 ) __a = ( 1.0 ) ; __typeof__ ( minDimension * ( 0.5 - ( 0.05 ) ) ) __b = ( minDimension * ( 0.5 - ( 0.05 ) ) ) ; __a < __b ? __b : __a ; } )(1.0,minDimension*(0.5-HYSTERESIS)))) { |
| 429 | return [self RB___collapse]; |
| 430 | } |
| 431 | newdim = minDimension; |
| 432 | } |
| 433 | } else if (newdim>olddim) { |
| 434 | if (olddim<1.0) { |
| 435 | // Expand if needed. |
| 436 | if (newdim>(minDimension*(0.5+HYSTERESIS( 0.05 )))) { |
| 437 | newdim = MAX( { __typeof__ ( newdim ) __a = ( newdim ) ; __typeof__ ( [ self RB___expandAndSetToMinimum : ( BOOL ) 1 ] ) __b = ( [ self RB___expandAndSetToMinimum : ( BOOL ) 1 ] ) ; __a < __b ? __b : __a ; } )(newdim,[self RB___expandAndSetToMinimum:YES]); |
| 438 | } else { |
| 439 | return 0.0; |
| 440 | } |
| 441 | } |
| 442 | if (newdim>maxDimension) { |
| 443 | newdim = maxDimension; |
| 444 | } |
| 445 | } |
| 446 | if ((int)newdim!=(int)olddim) { |
| 447 | // The dimension has changed. |
| 448 | increment = newdim-olddim; |
| 449 | DIM( ( ( float * ) & ( frame . size ) ) [ ishor ] )(frame.size) = newdim; |
| 450 | if (move) { |
| 451 | DIM( ( ( float * ) & ( frame . origin ) ) [ ishor ] )(frame.origin) -= increment; |
| 452 | } |
| 453 | // We call super instead of self here to postpone adjusting subviews for nested splitviews. |
| 454 | // [super setFrameSize:frame.size]; |
| 455 | [super setFrame:frame]; |
| 456 | [sv RB___setMustClearFractions]; |
| 457 | [sv setMustAdjust]; |
| 458 | } |
| 459 | return newdim-olddim; |
| 460 | } |
| 461 | |
| 462 | // This convenience method returns the number of subviews (surprise!) |
| 463 | - (unsigned)numberOfSubviews { |
| 464 | return [[self subviews] count]; |
| 465 | } |
| 466 | |
| 467 | // We return the deepest subview that's hit by aPoint. We also check with the delegate if aPoint is |
| 468 | // within an alternate drag view. |
| 469 | - (NSView*)hitTest:(NSPoint)aPoint { |
| 470 | RBSplitView* sv = [self splitView]; |
| 471 | if ([self mouse:aPoint inRect:[self frame]]) { |
| 472 | id delegate = [sv delegate]; |
| 473 | if ([delegate respondsToSelector:@selector(splitView:dividerForPoint:inSubview:)]) { |
| 474 | actDivider = [delegate splitView:sv dividerForPoint:aPoint inSubview:self]; |
| 475 | if ((int)actDivider<(int)([sv RB___numberOfSubviews]-1)) { |
| 476 | return self; |
| 477 | } |
| 478 | } |
| 479 | actDivider = NSNotFound; |
| 480 | NSView* result = [super hitTest:aPoint]; |
| 481 | canDragWindow = ![result isOpaque]; |
| 482 | return result; |
| 483 | } |
| 484 | return nil0; |
| 485 | } |
| 486 | |
| 487 | // This method handles clicking and dragging in an empty portion of the subview, or in an alternate |
| 488 | // drag view as designated by the delegate. |
| 489 | - (void)mouseDown:(NSEvent*)theEvent { |
| 490 | NSWindow* window = [self window]; |
| 491 | NSPoint where = [theEvent locationInWindow]; |
| 492 | if (actDivider<NSNotFound) { |
| 493 | // The mouse down was inside an alternate drag view; actDivider was just set in hitTest. |
| 494 | RBSplitView* sv = [self splitView]; |
| 495 | NSPoint point = [sv convertPoint:where fromView:nil0]; |
| 496 | [[RBSplitView cursor:RBSVDragCursor] push]; |
| 497 | NSPoint base = NSZeroPoint; |
| 498 | // Record the current divider coordinate. |
| 499 | float divc = [sv RB___dividerOrigin:actDivider]; |
| 500 | BOOL ishor = [sv isHorizontal]; |
| 501 | [sv RB___setDragging:YES( BOOL ) 1]; |
| 502 | // Loop while the button is down. |
| 503 | while ((theEvent = [NSApp nextEventMatchingMask:NSLeftMouseDownMask|NSLeftMouseDraggedMask|NSLeftMouseUpMask untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:YES( BOOL ) 1])&&([theEvent type]!=NSLeftMouseUp)) { |
| 504 | // Set up a local autorelease pool for the loop to prevent buildup of temporary objects. |
| 505 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
| 506 | NSDisableScreenUpdates(); |
| 507 | // This does the actual movement. |
| 508 | [sv RB___trackMouseEvent:theEvent from:point withBase:base inDivider:actDivider]; |
| 509 | if ([sv mustAdjust]) { |
| 510 | // If something changed, we clear fractions and redisplay. |
| 511 | [sv RB___setMustClearFractions]; |
| 512 | [sv display]; |
| 513 | } |
| 514 | // Change the drag point by the actual amount moved. |
| 515 | float newc = [sv RB___dividerOrigin:actDivider]; |
| 516 | DIM( ( ( float * ) & ( point ) ) [ ishor ] )(point) += newc-divc; |
| 517 | divc = newc; |
| 518 | NSEnableScreenUpdates(); |
| 519 | [pool release]; |
| 520 | } |
| 521 | [sv RB___setDragging:NO( BOOL ) 0]; |
| 522 | [NSCursor pop]; |
| 523 | actDivider = NSNotFound; |
| 524 | return; |
| 525 | } |
| 526 | if (canDragWindow&&[window isMovableByWindowBackground]&&![[self couplingSplitView] background]) { |
| 527 | // If we get here, it's a textured (metal) window, the mouse has gone down on an non-opaque portion |
| 528 | // of the subview, and our RBSplitView has a transparent background. RBSplitView returns NO to |
| 529 | // mouseDownCanMoveWindow, but the window should move here - after all, the window background |
| 530 | // is visible right here! So we fake it and move the window as intended. Mwahahaha! |
| 531 | where = [window convertBaseToScreen:where]; |
| 532 | NSPoint origin = [window frame].origin; |
| 533 | // Now we loop handling mouse events until we get a mouse up event. |
| 534 | while ((theEvent = [NSApp nextEventMatchingMask:NSLeftMouseDownMask|NSLeftMouseDraggedMask|NSLeftMouseUpMask untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:YES( BOOL ) 1])&&([theEvent type]!=NSLeftMouseUp)) { |
| 535 | // Set up a local autorelease pool for the loop to prevent buildup of temporary objects. |
| 536 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
| 537 | NSPoint now = [window convertBaseToScreen:[theEvent locationInWindow]]; |
| 538 | origin.x += now.x-where.x; |
| 539 | origin.y += now.y-where.y; |
| 540 | // Move the window by the mouse displacement since the last event. |
| 541 | [window setFrameOrigin:origin]; |
| 542 | where = now; |
| 543 | [pool release]; |
| 544 | } |
| 545 | } |
| 546 | } |
| 547 | |
| 548 | // These two methods encode and decode subviews. |
| 549 | - (void)encodeWithCoder:(NSCoder*)coder { |
| 550 | NSRect frame; |
| 551 | BOOL coll = [self isCollapsed]; |
| 552 | if (coll) { |
| 553 | // We can't encode a collapsed subview as-is, so we correct the frame size first and add WAYOUT |
| 554 | // to the origin to signal it was collapsed. |
| 555 | NSRect newf = frame = [self frame]; |
| 556 | newf.origin.x += WAYOUT( 1000000.0 ); |
| 557 | [super setFrameOrigin:newf.origin]; |
| 558 | newf.size = savedSize; |
| 559 | [super setFrameSize:newf.size]; |
| 560 | } |
| 561 | [super encodeWithCoder:coder]; |
| 562 | if (coll) { |
| 563 | [super setFrame:frame]; |
| 564 | } |
| 565 | if ([coder allowsKeyedCoding]) { |
| 566 | [coder encodeObject:identifier forKey:@"identifier"]; |
| 567 | [coder encodeInt:tag forKey:@"tag"]; |
| 568 | [coder encodeFloat:minDimension forKey:@"minDimension"]; |
| 569 | [coder encodeFloat:maxDimension forKey:@"maxDimension"]; |
| 570 | [coder encodeDouble:fraction forKey:@"fraction"]; |
| 571 | [coder encodeBool:canCollapse forKey:@"canCollapse"]; |
| 572 | } else { |
| 573 | [coder encodeObject:identifier]; |
| 574 | [coder encodeValueOfObjCType:@encode(typeof(tag)) at:&tag]; |
| 575 | [coder encodeValueOfObjCType:@encode(typeof(minDimension)) at:&minDimension]; |
| 576 | [coder encodeValueOfObjCType:@encode(typeof(maxDimension)) at:&maxDimension]; |
| 577 | [coder encodeValueOfObjCType:@encode(typeof(fraction)) at:&fraction]; |
| 578 | [coder encodeValueOfObjCType:@encode(typeof(canCollapse)) at:&canCollapse]; |
| 579 | } |
| 580 | } |
| 581 | |
| 582 | - (id)initWithCoder:(NSCoder*)coder { |
| 583 | if ((self = [super initWithCoder:coder])) { |
| 584 | fraction = 0.0; |
| 585 | canCollapse = NO( BOOL ) 0; |
| 586 | notInLimits = NO( BOOL ) 0; |
| 587 | minDimension = 1.0; |
| 588 | maxDimension = WAYOUT( 1000000.0 ); |
| 589 | identifier = @""; |
| 590 | actDivider = NSNotFound; |
| 591 | canDragWindow = NO( BOOL ) 0; |
| 592 | previous = [self frame]; |
| 593 | savedSize = previous.size; |
| 594 | if (previous.origin.x>=WAYOUT( 1000000.0 )) { |
| 595 | // The subview was collapsed when encoded, so we correct the origin and collapse it. |
| 596 | BOOL ishor = [self splitViewIsHorizontal]; |
| 597 | previous.origin.x -= WAYOUT( 1000000.0 ); |
| 598 | DIM( ( ( float * ) & ( previous . size ) ) [ ishor ] )(previous.size) = 0.0; |
| 599 | [self setFrameOrigin:previous.origin]; |
| 600 | [self setFrameSize:previous.size]; |
| 601 | } |
| 602 | previous = NSZeroRect; |
| 603 | if ([coder allowsKeyedCoding]) { |
| 604 | [self setIdentifier:[coder decodeObjectForKey:@"identifier"]]; |
| 605 | tag = [coder decodeIntForKey:@"tag"]; |
| 606 | minDimension = [coder decodeFloatForKey:@"minDimension"]; |
| 607 | maxDimension = [coder decodeFloatForKey:@"maxDimension"]; |
| 608 | fraction = [coder decodeDoubleForKey:@"fraction"]; |
| 609 | canCollapse = [coder decodeBoolForKey:@"canCollapse"]; |
| 610 | } else { |
| 611 | [self setIdentifier:[coder decodeObject]]; |
| 612 | [coder decodeValueOfObjCType:@encode(typeof(tag)) at:&tag]; |
| 613 | [coder decodeValueOfObjCType:@encode(typeof(minDimension)) at:&minDimension]; |
| 614 | [coder decodeValueOfObjCType:@encode(typeof(maxDimension)) at:&maxDimension]; |
| 615 | [coder decodeValueOfObjCType:@encode(typeof(fraction)) at:&fraction]; |
| 616 | [coder decodeValueOfObjCType:@encode(typeof(canCollapse)) at:&canCollapse]; |
| 617 | } |
| 618 | } |
| 619 | return self; |
| 620 | } |
| 621 | |
| 622 | @end |
| 623 | |
| 624 | @implementation RBSplitSubview (RB___SubviewAdditions) |
| 625 | |
| 626 | // This hides/shows the subview without calling adjustSubview. |
| 627 | - (void)RB___setHidden:(BOOL)flag { |
| 628 | [super setHidden:flag]; |
| 629 | } |
| 630 | |
| 631 | // This internal method returns the current animationData. It will always return nil if |
| 632 | // the receiver isn't the current owner and some other subview is already being animated. |
| 633 | // Otherwise, if the parameter is YES, a new animation will be started (or the current |
| 634 | // one will be restarted). |
| 635 | - (animationData*)RB___animationData:(BOOL)start resize:(BOOL)resize { |
| 636 | if (currentAnimation&&(currentAnimation->owner!=self)) { |
| 637 | // There already is an animation in progress on some other subview. |
| 638 | return nil0; |
| 639 | } |
| 640 | if (start) { |
| 641 | // We want to start (or restart) an animation. |
| 642 | RBSplitView* sv = [self splitView]; |
| 643 | if (sv) { |
| 644 | float dim = [self dimension]; |
| 645 | // First assume the default time, then ask the delegate. |
| 646 | NSTimeInterval total = dim*(0.2/150.0); |
| 647 | id delegate = [sv delegate]; |
| 648 | if ([delegate respondsToSelector:@selector(splitView:willAnimateSubview:withDimension:)]) { |
| 649 | total = [delegate splitView:sv willAnimateSubview:self withDimension:dim]; |
| 650 | } |
| 651 | // No use animating anything shorter than the frametime. |
| 652 | if (total>FRAMETIME( 1.0 / 60.0 )) { |
| 653 | if (!currentAnimation) { |
| 654 | currentAnimation = (animationData*)malloc(sizeof(animationData)); |
| 655 | } |
| 656 | if (currentAnimation) { |
| 657 | currentAnimation->owner = self; |
| 658 | currentAnimation->stepsDone = 0; |
| 659 | currentAnimation->elapsedTime = 0.0; |
| 660 | currentAnimation->dimension = dim; |
| 661 | currentAnimation->collapsing = ![self isCollapsed]; |
| 662 | currentAnimation->totalTime = total; |
| 663 | currentAnimation->finishTime = [NSDate timeIntervalSinceReferenceDate]+total; |
| 664 | currentAnimation->resizing = resize; |
| 665 | [sv RB___setDragging:YES( BOOL ) 1]; |
| 666 | } |
| 667 | } else if (currentAnimation) { |
| 668 | free(currentAnimation); |
| 669 | currentAnimation = NULL( ( void * ) 0 ); |
| 670 | } |
| 671 | } |
| 672 | } |
| 673 | return currentAnimation; |
| 674 | } |
| 675 | |
| 676 | // This internal method steps the animation to the next frame. |
| 677 | - (void)RB___stepAnimation { |
| 678 | NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate]; |
| 679 | animationData* anim = [self RB___animationData:NO( BOOL ) 0 resize:NO( BOOL ) 0]; |
| 680 | if (anim) { |
| 681 | RBSplitView* sv = [self splitView]; |
| 682 | NSTimeInterval remain = anim->finishTime-now; |
| 683 | NSRect frame = [self frame]; |
| 684 | BOOL ishor = [sv isHorizontal]; |
| 685 | // Continuing animation only makes sense if we still have at least FRAMETIME available. |
| 686 | if (remain>=FRAMETIME( 1.0 / 60.0 )) { |
Value stored to 'dim' during its initialization is never read | |
| 687 | float dim = DIM( ( ( float * ) & ( frame . size ) ) [ ishor ] )(frame.size); |
| 688 | float avg = anim->elapsedTime; |
| 689 | // We try to keep a record of how long it takes, on the average, to resize and adjust |
| 690 | // one animation frame. |
| 691 | if (anim->stepsDone) { |
| 692 | avg /= anim->stepsDone; |
| 693 | } |
| 694 | NSTimeInterval delay = MIN( { __typeof__ ( 0.0 ) __a = ( 0.0 ) ; __typeof__ ( ( 1.0 / 60.0 ) - avg ) __b = ( ( 1.0 / 60.0 ) - avg ) ; __a < __b ? __a : __b ; } )(0.0,FRAMETIME-avg); |
| 695 | // We adjust the new dimension proportionally to how much of the designated time has passed. |
| 696 | dim = floorf(anim->dimension*(remain-avg)/anim->totalTime); |
| 697 | if (dim>4.0) { |
| 698 | if (!anim->collapsing) { |
| 699 | dim = anim->dimension-dim; |
| 700 | } |
| 701 | DIM( ( ( float * ) & ( frame . size ) ) [ ishor ] )(frame.size) = dim; |
| 702 | [self RB___setFrame:frame withFraction:0.0 notify:NO( BOOL ) 0]; |
| 703 | [sv adjustSubviews]; |
| 704 | [self display]; |
| 705 | anim->elapsedTime += [NSDate timeIntervalSinceReferenceDate]-now; |
| 706 | ++anim->stepsDone; |
| 707 | // Schedule a timer to do the next animation step. |
| 708 | [self performSelector:@selector(RB___stepAnimation) withObject:nil0 afterDelay:delay inModes:[NSArray arrayWithObjects:NSDefaultRunLoopMode,NSModalPanelRunLoopMode, |
| 709 | NSEventTrackingRunLoopMode,nil0]]; |
| 710 | return; |
| 711 | } |
| 712 | } |
| 713 | // We're finished, either collapse or expand entirely now. |
| 714 | if (anim->collapsing) { |
| 715 | DIM( ( ( float * ) & ( frame . size ) ) [ ishor ] )(frame.size) = 0.0; |
| 716 | [self RB___finishCollapse:frame withFraction:anim->dimension/[sv RB___dimensionWithoutDividers]]; |
| 717 | } else { |
| 718 | float savemin,savemax; |
| 719 | float dim = [self RB___setMinAndMaxTo:anim->dimension savingMin:&savemin andMax:&savemax]; |
| 720 | DIM( ( ( float * ) & ( frame . size ) ) [ ishor ] )(frame.size) = dim; |
| 721 | [self RB___finishExpand:frame withFraction:0.0]; |
| 722 | minDimension = savemin; |
| 723 | maxDimension = savemax; |
| 724 | } |
| 725 | } |
| 726 | } |
| 727 | |
| 728 | // This internal method stops the animation, if the receiver is being animated. It will |
| 729 | // return YES if the animation was stopped. |
| 730 | - (BOOL)RB___stopAnimation { |
| 731 | if (currentAnimation&&(currentAnimation->owner==self)) { |
| 732 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(RB___stepAnimation) object:nil0]; |
| 733 | free(currentAnimation); |
| 734 | currentAnimation = NULL( ( void * ) 0 ); |
| 735 | [[self splitView] RB___setDragging:NO( BOOL ) 0]; |
| 736 | return YES( BOOL ) 1; |
| 737 | } |
| 738 | return NO( BOOL ) 0; |
| 739 | } |
| 740 | |
| 741 | // This internal method returns the actual visible dimension of the subview. Differs from -dimension in |
| 742 | // that it returns 0.0 if the subview is collapsed. |
| 743 | - (float)RB___visibleDimension { |
| 744 | BOOL ishor = [self splitViewIsHorizontal]; |
| 745 | NSRect frame = [self frame]; |
| 746 | return MAX( { __typeof__ ( 0.0 ) __a = ( 0.0 ) ; __typeof__ ( ( ( ( float * ) & ( frame . size ) ) [ ishor ] ) ) __b = ( ( ( ( float * ) & ( frame . size ) ) [ ishor ] ) ) ; __a < __b ? __b : __a ; } )(0.0,DIM(frame.size)); |
| 747 | } |
| 748 | |
| 749 | // This pair of internal methods is used only inside -[RBSplitView adjustSubviews] to copy subview data |
| 750 | // from and to that method's internal cache. |
| 751 | - (void)RB___copyIntoCache:(subviewCache*)cache { |
| 752 | cache->sub = self; |
| 753 | cache->rect = [self frame]; |
| 754 | cache->size = [self RB___visibleDimension]; |
| 755 | cache->fraction = fraction; |
| 756 | cache->constrain = NO( BOOL ) 0; |
| 757 | } |
| 758 | |
| 759 | - (void)RB___updateFromCache:(subviewCache*)cache withTotalDimension:(float)value { |
| 760 | float dim = [self RB___visibleDimension]; |
| 761 | if (cache->size>=1.0) { |
| 762 | // New state is not collapsed. |
| 763 | if (dim>=1.0) { |
| 764 | // Old state was not collapsed, so we just change the frame. |
| 765 | [self RB___setFrame:cache->rect withFraction:cache->fraction notify:YES( BOOL ) 1]; |
| 766 | } else { |
| 767 | // Old state was collapsed, so we expand it. |
| 768 | [self RB___finishExpand:cache->rect withFraction:cache->fraction]; |
| 769 | } |
| 770 | } else { |
| 771 | // New state is collapsed. |
| 772 | if (dim>=1.0) { |
| 773 | // Old state was not collapsed, so we clear first responder and change the frame. |
| 774 | [self RB___clearResponder]; |
| 775 | [self RB___finishCollapse:cache->rect withFraction:dim/value]; |
| 776 | } else { |
| 777 | // It was collapsed already, but the frame may have changed, so we set it. |
| 778 | [self RB___setFrame:cache->rect withFraction:cache->fraction notify:YES( BOOL ) 1]; |
| 779 | } |
| 780 | } |
| 781 | } |
| 782 | |
| 783 | // This internal method sets minimum and maximum values to the same value, saves the old values, |
| 784 | // and returns the new value (which will be limited to the old values). |
| 785 | - (float)RB___setMinAndMaxTo:(float)value savingMin:(float*)oldmin andMax:(float*)oldmax { |
| 786 | *oldmin = [self minDimension]; |
| 787 | *oldmax = [self maxDimension]; |
| 788 | if (value<*oldmin) { |
| 789 | value = *oldmin; |
| 790 | } |
| 791 | if (value>*oldmax) { |
| 792 | value = *oldmax; |
| 793 | } |
| 794 | minDimension = maxDimension = value; |
| 795 | return value; |
| 796 | } |
| 797 | |
| 798 | // This internal method tries to clear the first responder, if the current responder is a descendant of |
| 799 | // the receiving subview. If so, it will set first responder to nil, redisplay the former responder and |
| 800 | // return YES. Returns NO otherwise. |
| 801 | - (BOOL)RB___clearResponder { |
| 802 | NSWindow* window = [self window]; |
| 803 | if (window) { |
| 804 | NSView* responder = (NSView*)[window firstResponder]; |
| 805 | if (responder&&[responder respondsToSelector:@selector(isDescendantOf:)]) { |
| 806 | if ([responder isDescendantOf:self]) { |
| 807 | if ([window makeFirstResponder:nil0]) { |
| 808 | [responder display]; |
| 809 | return YES( BOOL ) 1; |
| 810 | } |
| 811 | } |
| 812 | } |
| 813 | } |
| 814 | return NO( BOOL ) 0; |
| 815 | } |
| 816 | |
| 817 | // This internal method collapses a subview. |
| 818 | // It returns the negative of the size of the subview before collapsing, or 0.0 if it wasn't collapsed. |
| 819 | - (float)RB___collapse { |
| 820 | float result = 0.0; |
| 821 | if (![self isCollapsed]) { |
| 822 | RBSplitView* sv = [self splitView]; |
| 823 | if (sv&&[self canCollapse]) { |
| 824 | [self RB___clearResponder]; |
| 825 | NSRect frame = [self frame]; |
| 826 | BOOL ishor = [sv isHorizontal]; |
| 827 | result = DIM( ( ( float * ) & ( frame . size ) ) [ ishor ] )(frame.size); |
| 828 | // For collapsed views, fraction will contain the fraction of the dimension previously occupied |
| 829 | DIM( ( ( float * ) & ( frame . size ) ) [ ishor ] )(frame.size) = 0.0; |
| 830 | [self RB___finishCollapse:frame withFraction:result/[sv RB___dimensionWithoutDividers]]; |
| 831 | } |
| 832 | } |
| 833 | return -result; |
| 834 | } |
| 835 | |
| 836 | // This internal method finishes the collapse of a subview, stopping the animation if |
| 837 | // there is one, and calling the delegate method if there is one. |
| 838 | - (void)RB___finishCollapse:(NSRect)rect withFraction:(double)value { |
| 839 | RBSplitView* sv = [self splitView]; |
| 840 | BOOL finish = [self RB___stopAnimation]; |
| 841 | [self RB___setFrame:rect withFraction:value notify:YES( BOOL ) 1]; |
| 842 | [sv RB___setMustClearFractions]; |
| 843 | if (finish) { |
| 844 | [self display]; |
| 845 | } |
| 846 | id delegate = [sv delegate]; |
| 847 | if ([delegate respondsToSelector:@selector(splitView:didCollapse:)]) { |
| 848 | [delegate splitView:sv didCollapse:self]; |
| 849 | } |
| 850 | } |
| 851 | |
| 852 | // This internal method expands a subview. setToMinimum will usually be YES during a divider drag. |
| 853 | // It returns the size of the subview after expanding, or 0.0 if it wasn't expanded. |
| 854 | - (float)RB___expandAndSetToMinimum:(BOOL)setToMinimum { |
| 855 | float result = 0.0; |
| 856 | RBSplitView* sv = [self splitView]; |
| 857 | if (sv&&[self isCollapsed]) { |
| 858 | NSRect frame = [super frame]; |
| 859 | double frac = fraction; |
| 860 | BOOL ishor = [sv isHorizontal]; |
| 861 | if (setToMinimum) { |
| 862 | result = DIM( ( ( float * ) & ( frame . size ) ) [ ishor ] )(frame.size) = minDimension; |
| 863 | } else { |
| 864 | result = [sv RB___dimensionWithoutDividers]*frac; |
| 865 | // We need to apply a compensation factor for proportional resizing in adjustSubviews. |
| 866 | float newdim = floorf((frac>=1.0)?result:result/(1.0-frac)); |
| 867 | DIM( ( ( float * ) & ( frame . size ) ) [ ishor ] )(frame.size) = newdim; |
| 868 | result = floorf(result); |
| 869 | } |
| 870 | [self RB___finishExpand:frame withFraction:0.0]; |
| 871 | } |
| 872 | return result; |
| 873 | } |
| 874 | |
| 875 | // This internal method finishes the the expansion of a subview, stopping the animation if |
| 876 | // there is one, and calling the delegate method if there is one. |
| 877 | - (void)RB___finishExpand:(NSRect)rect withFraction:(double)value { |
| 878 | RBSplitView* sv = [self splitView]; |
| 879 | BOOL finish = [self RB___stopAnimation]; |
| 880 | [self RB___setFrame:rect withFraction:value notify:YES( BOOL ) 1]; |
| 881 | [sv RB___setMustClearFractions]; |
| 882 | if (finish) { |
| 883 | [self display]; |
| 884 | } |
| 885 | id delegate = [sv delegate]; |
| 886 | if ([delegate respondsToSelector:@selector(splitView:didExpand:)]) { |
| 887 | [delegate splitView:sv didExpand:self]; |
| 888 | } |
| 889 | } |
| 890 | |
| 891 | // These internal methods set the subview's frame or size, and also store a fraction value |
| 892 | // which is used to ensure repeatability when the whole split view is resized. |
| 893 | - (void)RB___setFrame:(NSRect)rect withFraction:(double)value notify:(BOOL)notify { |
| 894 | RBSplitView* sv = [self splitView]; |
| 895 | id delegate = nil0; |
| 896 | if (notify) { |
| 897 | delegate = [sv delegate]; |
| 898 | // If the delegate method isn't implemented, we ignore the delegate altogether. |
| 899 | if ([delegate respondsToSelector:@selector(splitView:changedFrameOfSubview:from:to:)]) { |
| 900 | // If the rects are equal, the delegate isn't called. |
| 901 | if (NSEqualRects(previous,rect)) { |
| 902 | delegate = nil0; |
| 903 | } |
| 904 | } else { |
| 905 | delegate = nil0; |
| 906 | } |
| 907 | } |
| 908 | [sv setMustAdjust]; |
| 909 | [self setFrame:rect]; |
| 910 | fraction = value; |
| 911 | [delegate splitView:sv changedFrameOfSubview:self from:previous to:rect]; |
| 912 | previous = delegate?rect:NSZeroRect; |
| 913 | } |
| 914 | |
| 915 | - (void)RB___setFrameSize:(NSSize)size withFraction:(double)value { |
| 916 | [[self splitView] setMustAdjust]; |
| 917 | [self setFrameSize:size]; |
| 918 | fraction = value; |
| 919 | } |
| 920 | |
| 921 | // This internal method gets the fraction value. |
| 922 | - (double)RB___fraction { |
| 923 | return fraction; |
| 924 | } |
| 925 | |
| 926 | @end |
| 927 |