home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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 <dpsclient/psops.h>
- #import <dpsclient/wraps.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
-