home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1994 June / NEBULA_SE.ISO / SourceCode / MiscKit / Examples / TreeView / TreeView.m < prev   
Encoding:
Text File  |  1994-01-29  |  6.7 KB  |  282 lines

  1.  
  2. #import "TreeView.h"
  3. #import "TreeButton.h"
  4. #import "NamedTree.h"
  5. #import "Line.h"
  6.  
  7. // constants to determine how the buttons are laid out
  8. #define BUTTONWIDTH    155.0
  9. #define BUTTONHEIGHT     24.0
  10. #define VERTSPACING       8.0
  11. #define HORIZSPACING     40.0
  12.  
  13. @implementation TreeView
  14.  
  15. - initFrame:(const NXRect *)frameRect
  16. {
  17.   [super initFrame:frameRect];
  18.   [self setAutosizing:(unsigned int) (NX_WIDTHSIZABLE | NX_HEIGHTSIZABLE)];
  19.  
  20.   currentButton = nil;
  21.   lineList = nil;
  22.   priorButton = nil;
  23.   [selectedField setNextText: selectedField];
  24.   [selectedField setPreviousText: selectedField];
  25.   currScale  = 1.0;
  26.  
  27.   [self registerForDragging];
  28.   [self setOpaque:YES];
  29.  
  30.   return self;
  31. }
  32.  
  33. - buildTreeFromNode:aNode bottom:(double)ybot
  34.         top:(double)ytop atX:(double)xpos parent:(NXPoint *)pos
  35. {    // add a button representing the node to the View
  36.     // This method is recursive.
  37.     NXRect butFrame = {{(xpos + HORIZSPACING),
  38.             (ybot + (ytop - ybot) / 2 - BUTTONHEIGHT / 2)},
  39.             {BUTTONWIDTH, BUTTONHEIGHT}};
  40.     id newButton = [[[TreeButton alloc] initFrame:&butFrame]
  41.             setTreeNode:aNode];
  42.     id kid, kids = [aNode branches];
  43.     int numBranches = [kids count];
  44.     int i, treeWidth; double diff, accum = ybot;
  45.     NXPoint myCenter = {(NX_X(&butFrame)),
  46.                 (NX_Y(&butFrame) + BUTTONHEIGHT / 2)};
  47.     id newLine;
  48.     
  49.     [newButton setTitle:[aNode label]];
  50.     [self addSubview:newButton];
  51.     // line to parent:
  52.     if (pos) {    // NULL if root, so no line
  53.         NXPoint parentRight = { pos->x + BUTTONWIDTH, pos->y };
  54.         newLine = [[Line alloc] init];
  55.         [newLine setStart:&parentRight end:&myCenter];
  56.         [lineList addObject:newLine];
  57.     }
  58.     // now add any children and the lines to them.
  59.     for (i=numBranches - 1; i >= 0; i--) { // loop isn't entered if no kids.
  60.         kid = [kids objectAt:i];
  61.         treeWidth = [kid width];
  62.         diff = (treeWidth * (BUTTONHEIGHT + VERTSPACING));
  63.         [self buildTreeFromNode:kid bottom:accum
  64.                 top:(accum + diff + VERTSPACING)
  65.                 atX:(xpos + BUTTONWIDTH + HORIZSPACING)
  66.                 parent:&myCenter];
  67.         accum += diff;
  68.     }
  69.     return self;
  70. }
  71.  
  72. - attachTree:aTree
  73. {
  74.     int treeWidth = [aTree width];
  75.     int treeDepth = [aTree depth];
  76.     double height = (treeWidth * (BUTTONHEIGHT + VERTSPACING) + VERTSPACING);
  77.     double width  = (treeDepth * (BUTTONWIDTH + HORIZSPACING) + HORIZSPACING);
  78.     
  79.     treeRoot = aTree;
  80.     if (lineList) [[lineList freeObjects] free];
  81.     lineList = [[List alloc] init];
  82.     // resize the View to accomodate the Buttons
  83.     [self sizeTo:width :height];
  84.     [self buildTreeFromNode:aTree bottom:0.0 top:height atX:0.0 parent:NULL];
  85.  
  86.     return self;
  87. }
  88.  
  89. - drawSelf:(NXRect *)rects :(int)rectCount      // standard rendering method
  90. {
  91.     int i;
  92.     NXColor color = [[self window] backgroundColor];
  93.  
  94.     NXRectClip(rects);    // clipping will reduce rendering time a bit
  95.     // and is needed to keep lines from rendering outside the drawing area
  96.     
  97.     if (NXEqualColor(color, NX_COLORLTGRAY))
  98.        color = NX_COLORDKGRAY;
  99.  
  100.     // PSsetgray(NX_DKGRAY);
  101.     NXSetColor(color);
  102.     NXRectFill(&bounds);
  103.     // PSsetgray(NX_BLACK);
  104.     NXSetColor(NX_COLORBLACK);
  105.     PSsetlinewidth(2.0);
  106.  
  107.     for (i=0; i<[lineList count]; i++) // draw any lines in drawing area
  108.         [[lineList objectAt:i] renderIfInRect:rects];
  109.     for (i=0; i<[[self subviews] count]; i++) // redraw needed buttons
  110.         [[[self subviews] objectAt:i] display:rects :rectCount];
  111.         
  112.     return self;
  113. }
  114.  
  115. - scale:sender
  116. {
  117.   id popUp = [sender window];
  118.   short index = [popUp indexOfItem:[popUp selectedItem]];
  119.   //                   25%   50%  75%  100%  125%  150%  200%  SizeToFit
  120.   //                   0     1      2     3     4     5     6    7
  121.   float factors[] = {0.25,  0.50, 0.75,  1.0, 1.25, 1.50, 2.0, 0.20};
  122.   NXPoint center;
  123.   NXCoord scale = factors[index];
  124.  
  125.   // Initialize width and height bounds when view is not scaled.
  126.   if (currScale == 1.0)
  127.     {
  128.       origWidth = NX_WIDTH(&bounds);
  129.       origHeight = NX_HEIGHT(&bounds);
  130.     }
  131.  
  132.   // Remember the center to we can reset it after the scaling.
  133.   center.x = NX_X(&bounds) + NX_WIDTH(&bounds) / 2;
  134.   center.y = NX_Y(&bounds) + NX_HEIGHT(&bounds) / 2;
  135.  
  136.   // Scale the view to its new size
  137.   if (index == 3) // 100% (Normal Size)
  138.     {
  139.      [self setDrawSize:origWidth :origHeight];
  140.      currScale  = 1.0;
  141.     }
  142.   else
  143.     {
  144.       currScale *= scale;
  145.       [self setDrawSize:NX_WIDTH(&bounds) / currScale
  146.                        :NX_HEIGHT(&bounds) / currScale];
  147.     }
  148.  
  149.   // Reset the center point
  150.   [self setDrawOrigin:center.x - NX_WIDTH(&bounds) / 2
  151.               :center.y - NX_HEIGHT(&bounds) / 2];
  152.  
  153.   // Ensure that selected button, if any, is visible.
  154.   [self displayBut:currentButton];
  155.  
  156.   [self update];
  157.  
  158.   return self;
  159. }
  160.  
  161. - setCurrentButton:but
  162. {
  163.   if (but)
  164.     {
  165.       priorButton = currentButton;
  166.       if (priorButton)
  167.     {
  168.       [priorButton setType:NX_MOMENTARYPUSH];
  169.       [priorButton setState:0];
  170.     }
  171.       currentButton = but;
  172.       [currentButton setType:NX_ONOFF]; [currentButton setState:1];
  173.       // [selectedField setStringValueNoCopy: [but title]];
  174.     }
  175.   return but;
  176. }
  177.  
  178. - setCurrButtonByName:sender
  179. {
  180.   id currBut = [self getButByName:[sender stringValue]];
  181.  
  182.   [self displayBut:[self setCurrentButton:currBut]];
  183.   [treeRoot act:currBut];
  184.   return currBut;
  185. }
  186.  
  187. - getButByName:(const char*)name
  188. {
  189.   id butList = [self subviews];
  190.   id but = nil;
  191.   id currBut = nil;
  192.   int i = 0;
  193.  
  194.   while (!currBut && (but = [butList objectAt:i++]))
  195.     {
  196.       if (!strcmp([but title], name))
  197.     currBut = but;
  198.     }
  199.   return currBut;
  200. }
  201.  
  202. - displayButByName:sender
  203. {
  204.   id but = [self getButByName:[sender stringValue]];
  205.  
  206.   if (but)
  207.     [self displayBut:but];
  208.   return but;
  209. }
  210.  
  211. - displayBut:but
  212. {
  213.   NXRect butRect;
  214.  
  215.   if (but)
  216.     {
  217.       [[but getBounds:&butRect] convertRectToSuperview:&butRect];
  218.       [self scrollRectToVisible:&butRect];
  219.     }
  220.   return self;
  221. }
  222.  
  223. @end
  224.  
  225.  
  226.  
  227. // Color dragging support
  228.  
  229. BOOL includesType(const NXAtom *types, NXAtom type)
  230. {
  231.     if (types)
  232.       while (*types)
  233.     if (*types++ == type)
  234.       return YES;
  235.     return NO;
  236. }
  237.  
  238. @implementation TreeView(Drag)
  239.  
  240. - registerForDragging
  241. {
  242.  [self registerForDraggedTypes:&NXColorPboardType count:1];
  243.  return self;
  244. }
  245.  
  246. - (NXDragOperation)draggingEntered:(id <NXDraggingInfo>)sender
  247. {
  248. //  NXDragOperation sourceMask = [sender draggingSourceOperationMask];
  249.   Pasteboard *pboard = [sender draggingPasteboard];
  250.  
  251.   return ((includesType([pboard types], NXColorPboardType))
  252.        ? NX_DragOperationGeneric : NX_DragOperationNone);
  253. }
  254.  
  255. - (BOOL)prepareForDragOperation:(id <NXDraggingInfo>)sender
  256. {
  257.   return YES;
  258. }
  259.  
  260. - (BOOL)performDragOperation:(id <NXDraggingInfo>)sender
  261. {
  262.     Pasteboard *pboard = [sender draggingPasteboard];
  263.  
  264.     if (includesType([pboard types], NXColorPboardType))
  265.       {
  266.     NXColor color = NXReadColorFromPasteboard(pboard);
  267.     [[self window] setBackgroundColor:color];
  268.     [self display];  // reflect color change
  269.     return YES;
  270.       }
  271.     else
  272.       return NO;
  273. }
  274.  
  275. - concludeDragOperation:(id <NXDraggingInfo>)sender
  276. {
  277.   // Return value ignored.
  278.   return nil;
  279. }
  280.  
  281. @end
  282.