home *** CD-ROM | disk | FTP | other *** search
- // InspectorManager.m
- // By Kevin Brain (ksbrain@zeus.UWaterloo.ca)
-
- // A class that manages the displaying of elements of a list of view
- // objects that are periodically displayed and removed from a window.
-
- // Compositing techniques and functions from the ToolInspector example
- // by Sharon Biocca Zakhour, NeXT Developer Support Team
- // You may freely copy, distribute and reuse the code in this example.
- // *Everybody involved* disclaims any warranty of any kind, expressed
- // or implied, as to its fitness for any particular use.
-
- #import <objc/NXStringTable.h>
- #import <appkit/Panel.h>
- #import <appkit/View.h>
- #import <appkit/PopUpList.h>
- #import <appkit/Matrix.h>
- #import <objc/Storage.h>
- #import <objc/List.h>
- #import <appkit/Application.h> // for NXApp
- #import <dpsclient/wraps.h> // PScomposite
- #import <libc.h>
-
- #import "InspectorManager.h"
-
- @implementation InspectorManager
-
- /* Private functions */
- static void
- compositeToBuffer(InspectorManager *self,Window *bufferWindow, float srcX, float srcY,
- float width, float height, float dstX, float dstY)
- {
- [[bufferWindow contentView] lockFocus];
- PScomposite(srcX, srcY, width, height,
- [[self->inspectorPanel contentView] gState], dstX, dstY, NX_COPY);
- [[bufferWindow contentView] unlockFocus];
- }
-
- static void
- compositeToScreen(InspectorManager *self, Window *bufferWindow, float srcX, float srcY,
- float width, float height, float dstX, float dstY)
- {
- [[self->inspectorPanel contentView] lockFocus];
- PScomposite(srcX, srcY, width, height,
- [[bufferWindow contentView] gState], dstX, dstY, NX_COPY);
- [self->inspectorPanel flushWindow];
- [[self->inspectorPanel contentView] unlockFocus];
- }
-
- /* instance methods */
-
- - init
- {
- [super init];
- if ([NXApp loadNibSection:"Inspector.nib" owner:self] == nil)
- NXRunAlertPanel(NULL,"Couldn't load Inspector.nib","OK",NULL,NULL);
- /* Tell the Inspector & Palette panels not to become the key window */
- [inspectorPanel setBecomeKeyOnlyIfNeeded: YES]; /* This will only */
- /* work if you don't miniaturize the panel. */
- [inspectorPanel setFloatingPanel:(BOOL)YES];
- useKeyEquivalents = YES;
-
- inspectorList = [[Storage alloc] initCount:0 elementSize:sizeof(struct inspectorListEntry)
- description:@encode(struct inspectorListEntry)];
- groupList = [[Storage alloc] initCount:0 elementSize:sizeof(char *) description:"*"];
- visibleInspectors = [[Storage alloc] initCount:0 elementSize:sizeof(unsigned int) description:"i"];
- [revertOKOut removeFromSuperview];
- [popupOut removeFromSuperview];
- [inspectorPanel display]; // to actually remove the controls
- [[inspectorPanel contentView] allocateGState];
-
- /* 'messagePanel' is created in IB as the window containing the message inspector*/
- /* This window is non-deferred and always kept off-screen */
- [self addInspector: messageBox
- title:[inspectorStrings valueForStringKey: "MessageInspector"]
- atLocation:LOWERLEFTX :LOWERLEFTY cached:NO cacheWindow:messagePanel];
-
- /* Initialize the Inspector to display "Unapplicable Inspector" message */
- [self showMessage:(const char *)"Not\nApplicable"];
-
- return self;
- }
-
- - (unsigned int)addInspector:(id)theView title:(const char *)theTitle
- {
- return [self addInspector:theView title:theTitle
- atLocation:LOWERLEFTX :LOWERLEFTY cached:YES cacheWindow:nil];
- }
-
- - (unsigned int)addInspector:(id)theView title:(const char *)theTitle atLocation:(NXCoord)xLoc :(NXCoord)yLoc
- cached:(BOOL)isCached cacheWindow:(id)theCacheWindow
- {
- struct inspectorListEntry tempInspectorEntry;
- NXRect theViewRect;
-
- tempInspectorEntry.view = theView;
- tempInspectorEntry.showing = NO;
- tempInspectorEntry.cached = isCached;
- tempInspectorEntry.title = malloc(sizeof(char)*(strlen((char *)theTitle)));
- strcpy(tempInspectorEntry.title,theTitle);
-
- if (isCached) {
- if (theCacheWindow == nil) {
- [theView getFrame:&theViewRect];
- theViewRect.origin.x = [inspectorList count];
- tempInspectorEntry.cacheWindow = [[Window alloc] initContent:(const NXRect *)&theViewRect
- style:(int)NX_PLAINSTYLE
- backing:(int)NX_RETAINED
- buttonMask:(int)0
- defer:(BOOL)NO];
- }
- else
- tempInspectorEntry.cacheWindow = theCacheWindow;
- /* The lockFocus forces the gState to become defined */
- [[[tempInspectorEntry.cacheWindow contentView] allocateGState] lockFocus];
- [[tempInspectorEntry.cacheWindow contentView] addSubview:theView];
- if (theCacheWindow == nil) {
- [theView moveTo:0 :0]; // move view to origin of offscreen buffer content view
- [tempInspectorEntry.cacheWindow display];
- }
- [theView getFrame:&tempInspectorEntry.offscreenRect];
- // [theView display]; // draw in offscreen buffer
- [[tempInspectorEntry.cacheWindow contentView] unlockFocus];
- }
- [inspectorList addElement:&tempInspectorEntry];
-
- [theView moveTo:xLoc :yLoc];
- [theView removeFromSuperview];
- return [inspectorList count]-1;
- }
-
- - (unsigned int)addGroup:(const char *)theTitle
- {
- char *tempTitle;
- unsigned short temp;
- id tempView;
-
- // add item to PopUpList
- // command-key equivalents for first 9
- if (([groupList count] < 9) && (useKeyEquivalents == YES))
- temp = (unsigned short)[groupList count]+(unsigned short)'1';
- else
- temp = 0; // no command-key equivalent for rest
- tempView = [[popupOut target] addItem:theTitle
- action:@selector(selectGroup:)
- keyEquivalent:temp];
- [tempView setTarget:self];
- if ([groupList count] == 0) {
- // remove the default 'None' item in PopUpList
- [[popupOut target] removeItemAt:(unsigned int)0];
- [popupOut setTitle:theTitle];
- }
- if ([groupList count] == 1)
- [self showGroupPopUp];
- tempTitle = NXCopyStringBuffer((const char *)theTitle);
- [groupList addElement:&tempTitle];
- return [groupList count]-1;
- }
-
- - setUseKeyEquivalents:(BOOL)use
- {
- useKeyEquivalents = use;
- return self;
- }
-
- - switchToInspector:(unsigned int)newInspectorNum
- {
- struct inspectorListEntry *new,*tempOld;
- View *tempView;
- NXRect tempFrame;
- int i,*tempShowing;
- unsigned cnt = [visibleInspectors count];
-
- new = [inspectorList elementAt:newInspectorNum];
- if (!new) return self; // not a valid inspector
- if (new->showing == YES) return self; // if already showing
- /* remove all other inspectors */
- if (cnt)
- for (i=(int)cnt; i > 0;i--) {
- tempShowing = [visibleInspectors elementAt:i-1];
- tempOld = [inspectorList elementAt:(unsigned int)*tempShowing];
- tempOld->showing = NO;
- tempView = tempOld->view;
- if (tempView != NULL) {
- [tempView getFrame:&tempFrame];
- if (tempOld->cached)
- compositeToBuffer(self, tempOld->cacheWindow, tempFrame.origin.x, tempFrame.origin.y,
- NX_WIDTH(&tempFrame),NX_HEIGHT(&tempFrame),
- tempOld->offscreenRect.origin.x, tempOld->offscreenRect.origin.y);
- [tempView removeFromSuperview];
- }
- }
- [visibleInspectors empty];
-
- [[inspectorPanel contentView] addSubview:new->view];
- if (new->cached) {
- // Now composite the new inspector view from the offscreen window
- // into the inspector panel
- [new->view getFrame:&tempFrame];
- compositeToScreen(self, new->cacheWindow, new->offscreenRect.origin.x, new->offscreenRect.origin.y,
- NX_WIDTH(&tempFrame), NX_HEIGHT(&tempFrame), tempFrame.origin.x, tempFrame.origin.y);
- }
- else
- [new->view display];
-
- [inspectorPanel setTitle:new->title];
- new->showing = YES;
- i=(int)newInspectorNum;
- [visibleInspectors addElement:&i];
-
- return self;
- }
-
- - showInspector:(unsigned int)inspectorNum
- {
- struct inspectorListEntry *new;
- NXRect tempFrame;
- int tempNum;
-
- new = [inspectorList elementAt:inspectorNum];
- if (!new) return self; // not a valid inspector
-
- if ([self showing:inspectorNum] == YES) return self; // if already showing
-
- [inspectorPanel disableFlushWindow];
- [[inspectorPanel contentView] addSubview:new->view];
- if (new->cached) {
- // Now composite the new inspector view from the offscreen window
- // into the inspector panel
- [new->view getFrame:&tempFrame];
- compositeToScreen(self, new->cacheWindow, new->offscreenRect.origin.x, new->offscreenRect.origin.y,
- NX_WIDTH(&tempFrame), NX_HEIGHT(&tempFrame), tempFrame.origin.x, tempFrame.origin.y);
- }
- else
- [new->view display];
-
- [inspectorPanel setTitle:new->title];
- [inspectorPanel reenableFlushWindow];
- [inspectorPanel flushWindowIfNeeded];
- new->showing = YES;
- tempNum = (int)inspectorNum;
- [visibleInspectors addElement:&tempNum];
-
- return self;
- }
-
- - hideInspector:(unsigned int)inspectorNum
- {
- struct inspectorListEntry *inspector;
- View *tempView;
- NXRect tempFrame;
- int i,cnt = [visibleInspectors count],*tempNum;
-
- inspector = [inspectorList elementAt:inspectorNum];
- if (!inspector) return self; // not a valid inspector
- if(cnt) // find inspectorNum is visibleInspectors list
- for (i=cnt; i > 0;i--) {
- tempNum = [visibleInspectors elementAt:i-1];
- if (inspectorNum == (unsigned)*tempNum) {
- [visibleInspectors removeAt:(unsigned)i-1];
- inspector->showing = NO;
- tempView = inspector->view;
- if (tempView != NULL) {
- [tempView getFrame:&tempFrame];
- if (inspector->cached)
- compositeToBuffer(self, inspector->cacheWindow,
- tempFrame.origin.x, tempFrame.origin.y,
- NX_WIDTH(&tempFrame),NX_HEIGHT(&tempFrame),
- inspector->offscreenRect.origin.x, inspector->offscreenRect.origin.y);
- [tempView removeFromSuperview];
- }
- }
- }
-
- return self;
- }
-
- - (BOOL)showing:(unsigned int)inspectorNum
- {
- struct inspectorListEntry *inspector;
-
- if (inspectorNum >= [inspectorList count]) return NO; // not a valid inspector
- else inspector = [inspectorList elementAt:(unsigned)inspectorNum];
-
- if (inspector->showing == YES) return YES;
- else return NO;
- }
-
- - (int)group
- {
- // check if a group is selected (none is initially)
- if ([[popupOut target] selectedItem] == NULL)
- return 0; // if no group selected, return default group (first group added)
- else
- return [[popupOut target] indexOfItem:[[popupOut target] selectedItem]];
- }
-
- - showMessage:(const char *)theMessage
- {
- [inspectorPanel disableFlushWindow];
- [self switchToInspector:MESSAGE];
- [messageTextField setStringValue:theMessage];
- [messageTextField display];
- [[inspectorPanel reenableFlushWindow] flushWindowIfNeeded];
- return self;
- }
-
- - messageTextField {return messageTextField; }
-
- - panel
- {
- return inspectorPanel;
- }
-
- - popUpListButton
- {
- return popupOut;
- }
-
- - revertOKMatrix
- {
- return revertOKOut;
- }
-
- - setDelegate:(id)anObject
- {
- delegate = anObject;
- return self;
- }
-
- - delegate
- {
- return delegate;
- }
-
- - selectGroup:sender
- // target of inspector panel group selector PopUpList
- {
- [popupOut setTitle:[[sender selectedCell] title]];
- [inspectorPanel orderFront:self];
- if ([delegate respondsTo:@selector(groupChanged:to:)])
- {
- [delegate groupChanged:self to:[sender selectedRow]];
- }
- return self;
- }
-
- - revertPressed:sender
- // target of inspector panel Revert button
- {
- if ([delegate respondsTo:@selector(inspectRevert)])
- {
- [delegate inspectRevert:self];
- }
- return self;
- }
-
- - okPressed:sender
- // target of inspector panel OK button
- {
- if ([delegate respondsTo:@selector(inspectOK)])
- {
- [delegate inspectOK:self];
- }
- return self;
- }
-
- - showRevertOK
- {
- [[inspectorPanel contentView] addSubview:revertOKOut];
- [revertOKOut display];
- return self;
- }
-
- - hideRevertOK
- {
- [revertOKOut removeFromSuperview];
- // uncomment the following line to have the Revert/OK buttons
- // automatically removed by displaying the contentView
- // (otherwise the image of the buttons will still be visible)
- // [[inspectorPanel contentView] display];
- return self;
- }
-
- - showGroupPopUp
- {
- [[inspectorPanel contentView] addSubview:popupOut];
- [popupOut display];
- return self;
- }
-
- - hideGroupPopUp
- {
- [popupOut removeFromSuperview];
- [[inspectorPanel contentView] display];
- return self;
- }
- @end
-
-