home *** CD-ROM | disk | FTP | other *** search
- #pragma .h #import <appkit/View.h>
- #pragma .h #import "Glyph.h"
- #import "GlyphView.h"
- #import <appkit/Application.h>
- #import <appkit/Window.h>
- #import <appkit/NXCursor.h>
- #import <dpsclient/psops.h>
- #import <dpsclient/wraps.h>
- #import <c.h>
- #import "/local/grd/CB/MenuManager.h"
- #import <appkit/ScrollView.h>
- #import <appkit/publicWraps.h>
- #import <objc/List.h>
-
- static id glyphViewList ;
-
- @implementation GlyphView: View
- { id fGView, bGView, scrollView ;
- Glyph *rootGlyph, *targetGlyph, *superGlyph ;
- int fGGState, bGGState ;
- NXRect targetFrame ; // targetGlyph's frame in my coord sys
- NXRect clipRect ; // clipping rectangle around targetGlyph
- NXRect visibleRect ; // visible portion of rootGlyph
- NXPoint mouseOffset ; // distance from mouse hit to target's origin
- BOOL rootIsTarget, isAWindow ;
- }
-
- + glyphViewList ;
- { // return the list of glyph views
- if(glyphViewList == nil)
- glyphViewList = [[List alloc] init] ;
- return glyphViewList ;
- }
-
- -blowUp ;
- // Provide visual feedback that the target glyph is
- // dying, then kill it.
- { NXRect aRect ;
- float dx, dy ;
- id aWin ;
- int i , knt = 20 ;
- // shrink window to nothing
- aWin = [fGView window] ;
- [aWin orderFront: self] ; // may be offscreen
- [aWin getFrame: &aRect] ;
- dx = aRect.size.width / (float) knt ;
- dy = aRect.size.height / (float) knt ;
- for(i = 0 ; i < knt ; i++)
- { [aWin sizeWindow: aRect.size.width :aRect.size.height] ;
- NXPing() ;
- aRect.size.width -= dx ;
- aRect.size.height -= dy ;
- }
- [aWin orderOut: self] ;
- [targetGlyph free] ; // actually, doesn't know how to free yet!
- targetGlyph = nil ;
- return self ;
- }
-
-
- -clipRect: (NXRect *) aRect toGlyph: (Glyph *) aGlyph ;
- // set aRect to the clipping rectangle imposed by aGlyph.
- // This involves calculating intersection rectangles
- // back to the rootGlyph. Just calculates the clipping
- // rectangle; does not actually set it.
- { if(aGlyph->flags.isRoot)
- { aRect->origin.x = aGlyph->frame.origin.x ;
- aRect->origin.y = aGlyph->frame.origin.y ;
- aRect->size.width = aGlyph->frame.size.width ;
- aRect->size.height = aGlyph->frame.size.height ;
- return self ;
- }
- else
- { NXRect bRect = {{0.0,0.0},{0.0,0.0}} ;
- [self clipRect: aRect toGlyph: aGlyph->ancestor] ;
- bRect.size.height = aGlyph->frame.size.height ;
- bRect.size.width = aGlyph->frame.size.width ;
- [aGlyph convertToRootGlyph: &bRect.origin] ;
- NXIntersectionRect(&bRect,aRect) ;
- }
- return self ;
- }
-
- -convertToScreen: (NXPoint *) aPnt ;
- // convert aPnt from my coord sys to screen coord sys
- { [self convertPoint: aPnt toView: nil] ;
- [window convertBaseToScreen: aPnt] ;
- return self ;
- }
-
-
- -drawSelf:(const NXRect *)rects :(int)rectCount ;
- { // drawSelf: does the displaying when my window
- // is first opened, when its resized, when its
- // scrolled, or when its unminiaturized.
- // composite background
- PScomposite(rects->origin.x,
- rects->origin.y,
- rects->size.width,
- rects->size.height,
- bGGState,
- rects->origin.x,
- rects->origin.y,
- NX_COPY) ;
- // and, if necessary, the foreground
- if(targetGlyph && NXIntersectsRect(rects, &targetFrame))
- { NXRect unionRect ;
- float x,y ;
- unionRect = targetFrame ;
- NXUnionRect(rects,&unionRect) ;
- x = unionRect.origin.x - targetFrame.origin.x ;
- y = unionRect.origin.y - targetFrame.origin.y ;
- PScomposite(x,
- y,
- unionRect.size.width,
- unionRect.size.height,
- fGGState,
- unionRect.origin.x,
- unionRect.origin.y,
- NX_SOVER) ;
- }
- return self ;
- }
-
- - handOff: (NXPoint *) aPnt ;
- { // Attempts to handOff: the current targetGlyph to another
- // glyphView, if aPnt (the current mouse point in screen coords)
- // is within that view. Deletes the target if it fails. In
- // either case, sets the targetGlyph to nil.
- NXRect visRect ;
- NXPoint thePnt ;
- int found, gWinNum, fGWinNum, targetWin, i, knt ;
- id theList, theView ;
- NXConvertWinNumToGlobal([[fGView window] windowNum],&fGWinNum) ;
- [[fGView window] orderOut: self] ; // don't find the fG window
- PSfindwindow(aPnt->x,aPnt->y,NX_ABOVE,0,
- &thePnt.x,&thePnt.y,&gWinNum,&found) ;
- if(!found)
- return nil ;
- NXConvertGlobalToWinNum(gWinNum, &targetWin) ;
- theList = [GlyphView glyphViewList] ;
- knt = [theList count] ;
- for(i = 0 ; i < knt ; i++)
- { if(( [[(theView = [theList objectAt: i]) window] windowNum]) == targetWin)
- { // we've got a candidate...
- NXPoint viewPnt ;
- viewPnt = *aPnt ;
- [[theView window] convertScreenToBase: &viewPnt] ;
- [theView convertPoint: &viewPnt fromView: nil] ;
- [[[theView superview] superview] getDocVisibleRect: &visRect] ;
- if(NXPointInRect(&viewPnt,&visRect)) // give it away...
- { viewPnt.x -= mouseOffset.x ;
- viewPnt.y -= mouseOffset.y ;
- [theView receive: targetGlyph at: &viewPnt] ;
- targetGlyph = nil ;
- return self ;
- }
- else
- [self blowUp] ;
- break ;
- }
- }
- return nil ;
- }
-
-
- - mouseDown: (NXEvent *) anEvent ;
- { Glyph *tg ;
- BOOL newTarget = NO ;
- [self lockFocus] ;
- [self convertPoint: &anEvent->location fromView: nil] ;
- tg = [rootGlyph hitTest: &anEvent->location] ;
- if(tg != targetGlyph) // new target
- { [self newTarget: tg] ;
- newTarget = YES ;
- }
- if(tg == rootGlyph)
- { rootIsTarget = YES ;
- return self ;
- }
- rootIsTarget = NO ;
- // set the clipping rectangle
- PSgsave() ;
- superGlyph = tg->ancestor ;
- [self clipRect: &clipRect toGlyph: superGlyph] ;
- NXRectClip(&clipRect) ;
- // remove target glyph from TTree
- [targetGlyph unlink] ;
- // calculate new mouse offset
- mouseOffset.x = anEvent->location.x - targetFrame.origin.x ;
- mouseOffset.y = anEvent->location.y - targetFrame.origin.y ;
- isAWindow = false ; // initially, glyph must be in our view
- // finally, highlight the new target
- if(newTarget)
- { [self lockFocus] ;
- PSsetgray(0.666) ;
- PScompositerect(targetFrame.origin.x,targetFrame.origin.y,
- targetFrame.size.width,targetFrame.size.height, NX_PLUS) ;
- [self unlockFocus] ;
- [window flushWindow] ;
- }
- return self ;
- }
-
-
- - mouseDragged: (NXEvent *) anEvent ;
- { Glyph *aGlyph ;
- if(rootIsTarget)
- return self ; // can't drag the root glyph
- [self convertPoint: &anEvent->location fromView: nil] ;
- // see if we've dragged out of our window
- if(!isAWindow) // i.e. if glyph is in our view...
- { // erase our old image
- PScomposite(targetFrame.origin.x, targetFrame.origin.y,
- targetFrame.size.width, targetFrame.size.height,
- bGGState, targetFrame.origin.x, targetFrame.origin.y,NX_COPY) ;
- if(!NXPointInRect(&anEvent->location,&visibleRect)) // just dragged out of view...
- { NXPoint winPnt ; // turn into a "travelling window"
- winPnt.x = targetFrame.origin.x ;
- winPnt.y = targetFrame.origin.y ;
- [self convertToScreen: &winPnt] ;
- [[fGView window] moveTo: winPnt.x :winPnt.y] ;
- [[fGView window] orderFront: self] ;
- isAWindow = YES ;
- }
- }
- else // glyph dragged out of our view, so is a "travelling window"
- { if(NXPointInRect(&anEvent->location,&visibleRect)) // dragged back in?
- { [[fGView window] orderOut: self] ;
- isAWindow = NO ;
- }
- else // glyph was, and still is, a "travelling window"
- { NXPoint winPnt ; // move the "travelling window"
- winPnt.x = targetFrame.origin.x ;
- winPnt.y = targetFrame.origin.y ;
- [self convertPoint: &winPnt toView: nil] ;
- [window convertBaseToScreen:&winPnt] ;
- [[fGView window] moveTo: winPnt.x :winPnt.y] ;
- }
- }
- // update the target's location
- targetFrame.origin.x = anEvent->location.x - mouseOffset.x ;
- targetFrame.origin.y = anEvent->location.y - mouseOffset.y ;
- if(!isAWindow) // if not a "travelling window"....
- { // see if clip rectangle must change
- aGlyph = [rootGlyph hitTest: &anEvent->location] ;
- if(aGlyph && (aGlyph != superGlyph))
- { // must reset the clip rectangle
- superGlyph = aGlyph ;
- PSgrestore() ;
- PSgsave() ;
- [self clipRect: &clipRect toGlyph: superGlyph] ;
- NXRectClip(&clipRect) ;
- }
- // draw our new image
- PScomposite(0.0, 0.0,targetFrame.size.width,targetFrame.size.height,
- fGGState,targetFrame.origin.x, targetFrame.origin.y,NX_PLUS) ;
- // finally, highlight the new target
- [self lockFocus] ;
- PSsetgray(0.666) ;
- PScompositerect(targetFrame.origin.x,targetFrame.origin.y,
- targetFrame.size.width,targetFrame.size.height, NX_PLUS) ;
- [self unlockFocus] ;
- [window flushWindow] ;
- }
- return self ;
- }
-
- - mouseUp: (NXEvent *) anEvent ;
- { if(rootIsTarget)
- return self ;
- PSgrestore() ;
- [self unlockFocus] ;
- if(isAWindow)
- { [[self window] convertBaseToScreen: &anEvent->location] ;
- [self handOff: &anEvent->location] ; // hand it to another view, or the void!
- return self ;
- }
- [self convertPoint: &anEvent->location fromView: nil] ;
- // relink the target
- // Is the next hitTest necessary?
- superGlyph = [rootGlyph hitTest: &anEvent->location] ;
- [superGlyph convertFromRootGlyph: &anEvent->location] ;
- [targetGlyph moveTo: anEvent->location.x - mouseOffset.x
- : anEvent->location.y - mouseOffset.y ] ;
- [superGlyph plant: targetGlyph] ;
- return self ;
- }
-
-
- - newTarget: (Glyph *) tg ;
- { // This is called whenever a new target is selected.
- // (A smarter version
- // would know if the fg was "growing" or "shrinking".)
- // To repair the background, first composite the fGrnd
- // into the background...
- [bGView lockFocus] ;
- if(targetGlyph != nil)
- { // composite visible portion of old target into bGrnd
- NXIntersectionRect(&clipRect,&targetFrame) ;
- PScomposite(0.0,0.0,
- targetFrame.size.width,targetFrame.size.height,fGGState,
- targetFrame.origin.x, targetFrame.origin.y, NX_PLUS) ;
- targetGlyph->flags.isTarget = FALSE ;
- // repair the area in offscreen window
- [self lockFocus] ;
- PScomposite(targetFrame.origin.x,targetFrame.origin.y,
- targetFrame.size.width,targetFrame.size.height,bGGState,
- targetFrame.origin.x, targetFrame.origin.y, NX_COPY) ;
- [self unlockFocus] ;
- }
- // reset the targetGlyph ivars
- targetGlyph = tg ;
- tg->flags.isTarget = TRUE ;
- if(tg == rootGlyph) // life is easy if rootGlyph selected!
- { [window flushWindow] ;
- return self ;
- }
- else
- { // calculate the new target frame (location of
- // new target in my coord system)...
- targetFrame.origin.x = targetFrame.origin.y = 0.0 ;
- targetFrame.size.width = tg->frame.size.width ;
- targetFrame.size.height = tg->frame.size.height ;
- [tg convertToRootGlyph: &targetFrame.origin] ;
- // redraw background under targetFrame, without
- // redrawing the target Glyph itself...
- tg->flags.noDraw = TRUE ;
- [rootGlyph display: &targetFrame] ;
- tg->flags.noDraw = FALSE ;
- [bGView unlockFocus] ;
- // now draw the new target into the fGRnd window
- [fGView lockFocus] ;
- [[fGView window] sizeWindow: targetFrame.size.width
- :targetFrame.size.height] ;
- PSsetgray(1.0) ; // "clear" the old target
- PScompositerect(0.0, 0.0,
- targetFrame.size.width,targetFrame.size.height, NX_COPY) ;
- PSsetgray(0.0) ;
- [tg display: &tg->frame] ;
- [fGView unlockFocus] ;
- return self ;
- }
- }
-
- - receive: (Glyph *) aGlyt at: (NXPoint *) aPnt ;
- { // add the Glyt to my TTree, with aPnt its origin,
- // given in my coord sys
- Glyph * superG ;
- superG = [rootGlyph hitTest: aPnt] ;
- if(superG) // this should always be true
- { NXRect aRect ;
- aRect.origin = aGlyt->frame.origin = *aPnt ;
- aRect.size = aGlyt->frame.size ;
- [superG convertFromRootGlyph: &(aGlyt->frame.origin)] ;
- [superG plant: aGlyt] ;
- [bGView lockFocus] ;
- [rootGlyph display: &bounds] ; // aRect?
- [bGView unlockFocus] ;
- [self lockFocus] ;
- [self drawSelf: &aRect :1] ;
- [self unlockFocus] ;
- [window flushWindow] ;
- }
- return self ;
- }
-
- - rightMouseDown: (NXEvent *) anEvent ;
- { [window addToEventMask: NX_LMOUSEDRAGGEDMASK] ;
- [window addToEventMask: NX_RMOUSEDRAGGEDMASK] ;
- [NXApp printf: "D"] ;
- return self ;
- }
-
-
- - setScrollView: anObject ;
- { // this method is invoked curing nib file opening.
- // The opportunity is used to replace the scrollview's
- // docview with ourselves, then do initial setup
- scrollView = anObject ;
- [scrollView setHorizScrollerRequired: YES] ;
- [[scrollView setDocView: self] free] ;
- [self setup] ;
- return self ;
- }
-
-
- - setup ;
- { // perform initial setup of a
- // brand new window
- id bGWindow, fGWindow ;
- NXRect aRect = {{600.0,0.0},{1.0,1.0}} ;
- [window disableCursorRects] ;
- [window addToEventMask: NX_LMOUSEDRAGGEDMASK] ;
- [window addToEventMask: NX_RMOUSEDRAGGEDMASK] ;
- // create the background windows
- bGWindow = [Window new] ;
- [bGWindow initContent: &bounds style: NX_PLAINSTYLE
- backing: NX_RETAINED buttonMask:0 defer:NO] ;
- bGGState = [bGWindow gState] ; // MUST come AFTER initContent
- bGView = [bGWindow contentView] ;
- fGWindow = [Window new] ;
- [fGWindow initContent: &aRect style: NX_PLAINSTYLE
- backing: NX_RETAINED buttonMask:0 defer: NO] ;
- fGGState = [fGWindow gState] ;
- fGView = [fGWindow contentView] ;
- // setup the rootGlyph
- rootGlyph = [[Glyph alloc] init] ;
- rootGlyph->flags.isRoot = TRUE ;
- [rootGlyph sizeTo: frame.size.width :frame.size.height] ;
- [rootGlyph moveTo: 0.0 :0.0] ;
- // get current visible rectangle
- [[superview superview] getDocVisibleRect: &visibleRect] ;
- // add ourselves to list of glyph views
- [[GlyphView glyphViewList] addObject: self] ;
- // now cook them up for testing.. this will be
- // replaced by a display message to the rootglyph
- // with appropriate lockfocus
- [bGWindow orderFront: 0] ;
- [fGWindow orderFront: 0] ;
- { struct Glyph *aGlyph, *bGlyph, *cGlyph ;
- aGlyph = [[Glyph new] moveTo: 10.0 :15.0] ;
- bGlyph = [[Glyph new] moveTo: 25.0 :25.0] ;
- cGlyph = [[Glyph new] moveTo: 55.0 :55.0] ;
- [rootGlyph plant: aGlyph] ;
- [rootGlyph plant: bGlyph] ;
- [rootGlyph plant: cGlyph] ;
- [rootGlyph iam: "root"] ;
- [aGlyph iam: "a"] ;
- [bGlyph iam: "b"] ;
- [cGlyph iam: "c"] ;
- [bGView lockFocus] ;
- [rootGlyph display: &bounds] ;
- [bGView unlockFocus] ;
- }
-
- return self ;
- }
-
- - rightMouseDragged: (NXEvent *) anEvent ;
- { [NXApp printf: "R"] ;
- return self ;
- }
-
-
- - rightMouseUp: (NXEvent *) anEvent ;
- { [NXApp printf: "U"] ;
- return self ;
- }
-
- - windowDidResize: sender ;
- { NXRect aRect ;
- float x,y ;
- [superview getBounds: &aRect] ;
- [self sizeTo: x = MAX(bounds.size.width,aRect.size.width)
- : y = MAX(bounds.size.height,aRect.size.height)] ;
- [[bGView window] sizeWindow:x :y] ;
- [rootGlyph sizeTo: x :y] ;
- // NOTE: this generates 2 rectangles which will need to
- // be repaired in the bGView....
- // get current visible rectangle
- [[superview superview] getDocVisibleRect: &visibleRect] ;
- return self ;
- }
-
- - windowWillClose: sender ;
- { // our window is about to close; must free up
- // stuff we created
- [[fGView window] free] ;
- [[bGView window] free] ;
- [[GlyphView glyphViewList] removeObject: self] ;
- return self ;
- }
-
-
- @end