This is SideSplitView.m in view mode; [Download] [Up]
/* * SideSplitView.m * * Purpose: * This object implements a split view which divides a view into two * side by side areas. These areas are intended to be filled by subviews. * The user can then change the porportion of the subviews to one * another. The purpose is to provide developers with an alternative to * NXSplitView. * * You may freely copy, distribute, and reuse the code in this example. * NeXT disclaims any warranty of any kind, expressed or implied, as to its * fitness for any particular use. * * Written by: Mary McNabb * Created: Apr 91 * */ #import "SideSplitView.h" #import <appkit/NXImage.h> #import <dpsclient/psops.h> #import <dpsclient/wraps.h> #import <appkit/Application.h> #import <math.h> #import <libc.h> #define eventMask NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK #define DIVIDERWIDTH 8.0 /* the divider is 8 pixels wide. */ #define HALFWIDTH 4.0 static NXRect dimpleRect = {{3.0, 5.0}, {8.0, 7.0}}; /* Retrace is 1/67 of sec * 10^6 micro secs per second */ #define RETRACE (1000000.0/67.0) /* vertical retrace period in micro secs */ @implementation SideSplitView /* * initialize the split view. also initialize the size of the divider */ - initFrame:(NXRect *) theRect { NXSize dimpleSize; srandom(time(0)); /* initialize random number generator */ [super initFrame:theRect]; [self setAutoresizeSubviews:YES]; dimple = [NXImage findImageNamed:"Dimple"]; [dimple getSize:&dimpleSize]; dimpleHalfHeight = floor(dimpleSize.height / 2.0); dividerRect.origin.x = 0.0; dividerRect.origin.y = bounds.origin.y; dividerRect.size.height = bounds.size.height; dividerRect.size.width = dimpleSize.width + 3.0; minX = 0.0; return self; } /* * initialize the subviews of the split view. */ - initViews { [window disableFlushWindow]; [self adjustSubviews]; /* just in case we were sloppy in IB */ [window reenableFlushWindow]; [window flushWindow]; [self display]; return self; } /* * take advantage of IB. Use these set methods to initialize the subviews */ - setLeftView:(id)newView { NXRect leftViewFrame; leftView = newView; [leftView setAutosizing:NX_WIDTHSIZABLE| NX_HEIGHTSIZABLE|NX_MAXXMARGINSIZABLE]; [leftView getFrame:&leftViewFrame]; dividerRect.origin.x = leftViewFrame.size.width; [self addSubview:leftView]; return self; } /* * don't bother with the size and origin of the view as it gets completely reset in * adjustSubviews */ - setRightView:(id)newView { rightView = newView; [rightView setAutosizing:NX_WIDTHSIZABLE| NX_HEIGHTSIZABLE|NX_MINXMARGINSIZABLE]; [self addSubview:rightView]; return self; } - (BOOL)acceptsFirstMouse { return YES; } /* * The side split view consists of a light gray background, and a dimple. * Relies on the subviews to draw bevels, etc. */ - drawSelf:(const NXRect *)r :(int)c { NXPoint dimplePoint; PSsetgray(NX_LTGRAY); NXRectFill(&bounds); dimplePoint.x = dividerRect.origin.x + 1.0; dimplePoint.y = floor(dividerRect.origin.y + dividerRect.size.height / 2.0 - dimpleHalfHeight); [dimple composite:NX_SOVER toPoint:&dimplePoint]; return self; } /* * Controls the movement of the divider as the user slides it with the mouse */ - mouseDown:(NXEvent *) theEvent { NXPoint localPoint = theEvent->location; NXEvent *nextEvent; NXCoord lastX=0.0; int oldMask; [self convertPoint:&localPoint fromView:nil]; if (!NXMouseInRect(&localPoint, ÷rRect, NO)) return self; oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK]; /* We've gotten a mouse down on the divider, so go ahead and draw the slider now */ [self lockFocus]; PSsetinstance(YES); PSsetgray(.50); PSsetalpha(0.3333); PScompositerect(localPoint.x-HALFWIDTH, dividerRect.origin.y, DIVIDERWIDTH, dividerRect.size.height, NX_COPY); /* while the user is dragging composite a new slider in new postion -- watching for * boundary conditions. Exit loop on mouse up. */ do { nextEvent = [NXApp getNextEvent:eventMask]; localPoint = nextEvent->location; [self convertPoint:&localPoint fromView:nil]; if (localPoint.x < minX) localPoint.x = minX; if (localPoint.x > maxX) localPoint.x = maxX; if (localPoint.x != lastX) { /* wait some random amount of time within retrace period. */ usleep((random() % (int)RETRACE)); PSnewinstance(); PScompositerect(localPoint.x-HALFWIDTH, dividerRect.origin.y, DIVIDERWIDTH, dividerRect.size.height, NX_COPY); lastX = localPoint.x; } } while (nextEvent->type != NX_MOUSEUP); /* User is done dragging. Move the divider to new location */ dividerRect.origin.x = localPoint.x - HALFWIDTH; PSsetinstance(NO); [self unlockFocus]; [self adjustSubviews]; [self display]; [window setEventMask:oldMask]; return self; } /* * blits the dimple to the screen in the right spot */ - drawDimple { NXPoint origin; origin.x = dividerRect.origin.x; origin.y = floor(dividerRect.origin.y + dividerRect.size.height/2.0 - dimpleRect.size.height/2.0); [dimple composite:NX_COPY fromRect:&dimpleRect toPoint:&origin]; return self; } /* * modifies the size of the subviews after user has positioned the divider, or * has resized the window. * also used to initialize the sizes of the subviews. */ - adjustSubviews { NXRect leftViewFrame, rightViewFrame; /* first the left one */ [leftView getFrame:&leftViewFrame]; leftViewFrame.size.width = dividerRect.origin.x - leftViewFrame.origin.x; leftViewFrame.size.height = bounds.size.height; leftViewFrame.origin.x = bounds.origin.x; leftViewFrame.origin.y = bounds.origin.y; [leftView setFrame:&leftViewFrame]; [window invalidateCursorRectsForView:leftView]; /* then the right one */ [rightView getFrame:&rightViewFrame]; rightViewFrame.origin.x = leftViewFrame.size.width + DIVIDERWIDTH; rightViewFrame.origin.y = bounds.origin.y; rightViewFrame.size.width = bounds.size.width - rightViewFrame.origin.x; rightViewFrame.size.height = bounds.size.height; [rightView setFrame:&rightViewFrame]; [window invalidateCursorRectsForView:rightView]; /* update dividerRect in case of resize of window */ dividerRect.origin.x = leftViewFrame.size.width; dividerRect.size.height = leftViewFrame.size.height; dividerRect.origin.y = leftViewFrame.origin.y; maxX = bounds.size.width - HALFWIDTH; return self; } /* * called when the window gets resized */ - resizeSubviews:(const NXSize *)oldSize { [super resizeSubviews:oldSize]; [self adjustSubviews]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.