home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKit / Temp / Old / MiscMatrix.m < prev    next >
Encoding:
Text File  |  1995-04-12  |  22.2 KB  |  867 lines

  1. //
  2. //    MiscMatrix.m -- a class to implement variable-sized matrices
  3. //        Written by Mike Ferris Copyright (c) 1994 by Mike Ferris.
  4. //        Modified from original MOKit "MOMatrix" class by Don Yacktman.
  5. //                Version 1.0.  All rights reserved.
  6. //
  7. //        This notice may not be removed from this source code.
  8. //
  9. //    This object is included in the MiscKit by permission from the author
  10. //    and its use is governed by the MiscKit license, found in the file
  11. //    "LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
  12. //    for a list of all applicable permissions and restrictions.
  13. //    
  14.  
  15. // MiscMatrix is a subclass of Matrix that allows independantly sizable
  16. // rows and columns.  Each row can have a different height and each column
  17. // can have a different width.
  18. /*
  19.  *    Revision History:
  20.  *        July 1994:    Steve Quirk        steveq@telerate.com
  21.  *            - implemented sizeToFit method
  22.  *            - fixed bugs in addRow, addCol methods
  23.  *            - fixed bugs in initFrame:&etc&etc methods
  24.  *            - improved performance when changing row/column size
  25.  *        Aug 1994:    Steve Quirk
  26.  *            - improved drawing performance
  27.  *            - improved getRow:andCol:forPoint: performance
  28.  *        Sep 1994:  Scott Violet
  29.  *            - improved drawing performance; Scott's note:
  30.  *                In the code for drawSelf:: Mike chose to call drawCellAt::
  31.  *                which is very expensive, this will result in needless
  32.  *                lockFocus: and unlockFocus: calls, and this will make it
  33.  *                so that when the matrix is sent printPSCode: it won't work
  34.  *                (it tries to print it flipped).
  35.  */
  36.  
  37. #import <misckit/MiscMatrix.h>
  38. #import <objc/List.h>
  39. #import <objc/objc-runtime.h>
  40.  
  41. #define CLASS_VERSION         0
  42. #define CLASS_NAME            "MiscMatrix"
  43.  
  44. // These are the private methods we use in MiscMatrix
  45. @interface MiscMatrix(private)
  46.  
  47. - _Misc_copyRowSizes:rs andColSizes:cs zone:(NXZone *)zone;
  48. - _Misc_moveColumnsRightBy:(NXCoord)difference startingAt:(int)col;
  49. - _Misc_moveRowsDownBy:(NXCoord)difference startingAt:(int)row;
  50.  
  51. @end
  52.  
  53. @implementation MiscMatrix
  54.  
  55. + initialize
  56. // Set the class version
  57. {
  58.     if (self == objc_lookUpClass(CLASS_NAME))  {
  59.         [self setVersion:CLASS_VERSION];
  60.     }
  61.     return self;
  62. }
  63.  
  64. - setupStorage:(int)rowsHigh :(int)colsWide
  65. // Set up our storage objects
  66. {
  67.     int i;
  68.     MiscColumnSize newCSize;
  69.     MiscRowSize newRSize;
  70.     
  71.     columnSizes = [[Storage allocFromZone:[self zone]] initCount:0 
  72.                 elementSize:sizeof(MiscColumnSize)
  73.                 description:MISC_COLUMNSIZE_DESC];
  74.     [columnSizes setAvailableCapacity:(colsWide > 2) ? colsWide : 2];
  75.     rowSizes = [[Storage allocFromZone:[self zone]] initCount:0 
  76.                 elementSize:sizeof(MiscRowSize)
  77.                 description:MISC_ROWSIZE_DESC];
  78.     [rowSizes setAvailableCapacity:(rowsHigh > 2) ? rowsHigh : 2];
  79.     
  80.     newCSize.width = cellSize.width;
  81.     newRSize.height = cellSize.height;
  82.     for (i=0; i<colsWide; i++)  {
  83.         newCSize.x = bounds.origin.x + i * (cellSize.width + intercell.width);
  84.         [columnSizes addElement:&newCSize];
  85.     }
  86.     for (i=0; i<rowsHigh; i++)  {
  87.         newRSize.y = bounds.origin.y + i * (cellSize.height + intercell.height);
  88.         [rowSizes addElement:&newRSize];
  89.     }
  90.     
  91.     return self;
  92. }
  93.  
  94. - initFrame:(const NXRect *)frm mode:(int)aMode prototype:cellId 
  95.             numRows:(int)rowsHigh numCols:(int)colsWide
  96. // Designated initializer override from Matrix.  Sets up our storage stuff.
  97. {
  98.     [super initFrame:frm mode:aMode prototype:cellId numRows:rowsHigh 
  99.                 numCols:colsWide];
  100.     
  101.     [self setupStorage:rowsHigh :colsWide];
  102.     
  103.     return self;
  104. }
  105.  
  106. - initFrame:(const NXRect *)frm mode:(int)aMode cellClass:factoryId 
  107.             numRows:(int)rowsHigh numCols:(int)colsWide
  108. // Designated initializer override from Matrix.  Sets up our storage stuff.
  109. {
  110.     [super initFrame:frm mode:aMode cellClass:factoryId numRows:rowsHigh 
  111.                 numCols:colsWide];
  112.     
  113.     [self setupStorage:rowsHigh :colsWide];
  114.     
  115.     return self;
  116. }
  117.  
  118. - _Misc_copyRowSizes:rs andColSizes:cs zone:(NXZone *)zone
  119. {
  120.     rowSizes = [rs copyFromZone:zone];
  121.     columnSizes = [cs copyFromZone:zone];
  122.     return self;
  123. }
  124.  
  125. - copyFromZone:(NXZone *)zone
  126. {
  127.     id obj = [super copyFromZone:zone];
  128.     [obj _Misc_copyRowSizes:rowSizes andColSizes:columnSizes zone:zone];
  129.     return obj;
  130. }
  131.  
  132. - free
  133. // free the storage
  134. {
  135.     [columnSizes free];
  136.     [rowSizes free];
  137.     return [super free];
  138. }
  139.  
  140. - _Misc_moveColumnsRightBy:(NXCoord)difference startingAt:(int)col
  141. // A private method used by the methods which cause sizing stuff to change
  142. {
  143.     MiscColumnSize *cSize;
  144.     int i;
  145.  
  146.     if ((col < 0) || (col >= numCols))  {
  147.         return nil;
  148.     }
  149.  
  150.     cSize = (MiscColumnSize *)[columnSizes elementAt:col];
  151.     for (i=col; i<numCols; i++, cSize++)
  152.         cSize->x += difference;
  153.  
  154.     return self;
  155. }
  156.  
  157. - _Misc_moveRowsDownBy:(NXCoord)difference startingAt:(int)row
  158. // A private method used by the methods which cause sizing stuff to change
  159. {
  160.     MiscRowSize *rSize;
  161.     int i;
  162.     
  163.     if ((row < 0) || (row >= numRows))  {
  164.         return nil;
  165.     }
  166.  
  167.     rSize = (MiscRowSize *)[rowSizes elementAt:row];
  168.     for (i=row; i<numRows; i++, rSize++)
  169.         rSize->y += difference;
  170.  
  171.     return self;
  172. }
  173.  
  174. - setWidth:(NXCoord)newWidth ofCol:(int)col
  175. // This method allows the setting of column widths
  176. {
  177.     NXCoord diff;
  178.     MiscColumnSize *cSize;
  179.     
  180.     if ((col < 0) || (col >= numCols))  {
  181.         return nil;
  182.     }
  183.  
  184.     cSize = (MiscColumnSize *)[columnSizes elementAt:col];
  185.     diff = newWidth - cSize->width;
  186.     cSize->width = newWidth;
  187.     
  188.     return [self _Misc_moveColumnsRightBy:diff startingAt:col+1];
  189. }
  190.  
  191. - setHeight:(NXCoord)newHeight ofRow:(int)row
  192. // This method allows the setting of row heights
  193. {
  194.     NXCoord diff;
  195.     MiscRowSize *rSize;
  196.     
  197.     if ((row < 0) || (row >= numRows))  {
  198.         return nil;
  199.     }
  200.  
  201.     rSize = (MiscRowSize *)[rowSizes elementAt:row];
  202.     diff = newHeight - rSize->height;
  203.     rSize->height = newHeight;
  204.  
  205.     return [self _Misc_moveRowsDownBy:diff startingAt:row+1];
  206. }
  207.  
  208. - sizeToCells
  209. // Resize the matrix to the proper size to fit all our cells.
  210. {
  211.     NXRect rect;
  212.     MiscColumnSize *cSize;
  213.     MiscRowSize *rSize;
  214.     
  215.     [self getFrame:&rect];
  216.     
  217.     if (numCols == 0)  {
  218.         rect.size.width = 0.0;
  219.     }  else  {
  220.         cSize = (MiscColumnSize *)[columnSizes lastElement];
  221.         rect.size.width = cSize->x + cSize->width - bounds.origin.x;
  222.     }
  223.  
  224.     if (numRows == 0)  {
  225.         rect.size.height = 0.0;
  226.     }  else  {
  227.         rSize = (MiscRowSize *)[rowSizes lastElement];
  228.         rect.size.height = rSize->y + rSize->height - bounds.origin.y;
  229.     }
  230.     
  231.     /* Or do we want to just hit the instance variable directly--see the
  232.      * version at the end of -sizeRowsToFitCells where you _cannot_ use
  233.      * the -setFrame: method.  If you have troubles with this implementation,
  234.      * let the maintainer of the class know to change this so it will
  235.      * work right for everybody.
  236.      */
  237.     [self setFrame:&rect]; // I think we want self here, not super...  -DAY
  238.  
  239.     return self;
  240. }
  241.  
  242.  
  243. - sizeToFit
  244. /*
  245.  *    resize row heights and column widths to accommodate the largest cell in each
  246.  *    then resize self to fit the cells.
  247.  */
  248. {
  249.     int row,col;
  250.     NXSize thisCellSize;
  251.     MiscRowSize    *rSize;
  252.     MiscColumnSize *cSize;
  253.     NXCoord *maxWidth, *mW, maxHeight;
  254.     NXZone *myZone;
  255.     id    *cellAt;
  256.     /* 
  257.      *    This method is a pig.  Try to improve preformance by removing method calls
  258.      *    by using the method implementation ptr...
  259.      */
  260.     id (*cellCalcCellSize)(id, SEL, NXSize*);
  261.  
  262.     myZone = [super zone];
  263.     
  264.     // space to record the largest size of the columns
  265.     maxWidth = NXZoneCalloc(myZone, numCols, sizeof(NXCoord));
  266.  
  267.     /*
  268.      *    this monkey business is to speed up execution of this pig
  269.      */
  270.     cellCalcCellSize = (id(*)(id, SEL, NXSize*))
  271.         [protoCell methodFor:@selector(calcCellSize:)];
  272.     cellAt = ((List *)(cellList))->dataPtr;                // peek at Lists' data
  273.     
  274.     rSize = (MiscRowSize *)[rowSizes elementAt:0];
  275.     for (row = 0; row < numRows; row++,rSize++) {
  276.         maxHeight = rSize->height;                /* init max = height of cell 0 */
  277.         
  278.         for (col = 0, mW = maxWidth; col < numCols; col++, mW++) {
  279. //            [[super cellAt:row:col] calcCellSize:&thisCellSize];
  280.             //    replace above with....
  281.             cellCalcCellSize(*cellAt,@selector(calcCellSize:),&thisCellSize);
  282.             
  283.             if (thisCellSize.height > maxHeight)
  284.                 maxHeight = thisCellSize.height;
  285.             if (thisCellSize.width > *mW)
  286.                 *mW = thisCellSize.width;
  287.             cellAt++;    /* next column... */
  288.         }
  289.         /*
  290.          *    change the height of this row if one of the columns needs more headroom
  291.          */
  292.         if (maxHeight > rSize->height)
  293.             [self setHeight:maxHeight ofRow:row];
  294.     }
  295.  
  296.     /*
  297.      *    now adjust the column widths if needed...
  298.      */
  299.     cSize = (MiscColumnSize *)[columnSizes elementAt:0];
  300.     for (col = 0, mW = maxWidth; col < numCols; col++,cSize++, mW++)
  301.         if (*mW != cSize->width) {
  302.             NXCoord diff;
  303.             diff = *mW - cSize->width;
  304.             cSize->width = *mW;
  305.             [self _Misc_moveColumnsRightBy:diff startingAt:col+1];
  306.         }
  307.  
  308.     if (maxWidth)
  309.         NXZoneFree(myZone,maxWidth);
  310.  
  311.     return [self sizeToCells];
  312. }
  313.  
  314. - renewRows:(int)newRows cols:(int)newCols
  315. // Makes sure to keep our storage objects in synch with everything else.
  316. {
  317.     MiscColumnSize newCSize, *cSize;
  318.     MiscRowSize newRSize, *rSize;
  319.     int i;
  320.     
  321.     // Remove any storage elements past the new number of cols
  322.     for (i=numCols-1; i>=newCols; i--)  {
  323.         [columnSizes removeLastElement];
  324.     }
  325.     // Add any needed new storage elements to get up to the new number of cols
  326.     for (i=numCols; i<newCols; i++)  {
  327.         if (i==0)  {
  328.             newCSize.x = bounds.origin.x;
  329.         }  else  {
  330.             cSize = (MiscColumnSize *)[columnSizes lastElement];
  331.             newCSize.x = cSize->x + cSize->width + intercell.width;
  332.         }
  333.         newCSize.width = cellSize.width;
  334.         [columnSizes addElement:&newCSize];
  335.     }
  336.  
  337.     // Remove any storage elements past the new number of rows
  338.     for (i=numRows-1; i>=newRows; i--)  { // Was ++ but -- makes more sense
  339.         [rowSizes removeLastElement];
  340.     }
  341.     // Add any needed new storage elements to get up to the new number of rows
  342.     for (i=numRows; i<newRows; i++)  {
  343.         if (i==0)  {
  344.             newRSize.y = bounds.origin.y;
  345.         }  else  {
  346.             rSize = (MiscRowSize *)[rowSizes lastElement];
  347.             newRSize.y = rSize->y + rSize->height + intercell.height;
  348.         }
  349.         newRSize.height = cellSize.height;
  350.         [rowSizes addElement:&newRSize];
  351.     }
  352.     
  353.     [super renewRows:newRows cols:newCols];
  354.     
  355.     return self;
  356. }
  357.  
  358. - addCol
  359. /*
  360.  *    addCol is implemented by the Matrix superclass as [self insertColAt:numCols]
  361.  *    so doing all this work here is redundant (and wrong).  Changed this to simply
  362.  *    call super.
  363.  */
  364. {    
  365.     int n = [columnSizes count];        /*    copy just to prove a point... */
  366.     
  367.     [super addCol];
  368.     //    to prove my point, look how everything still checks out...
  369.     if (([columnSizes count] != (n+1)) || ((n+1) != numCols)) 
  370.           [self error:"Assertion failed in [MiscMatrix addCol]. Re-implement!"];
  371.  
  372.     return self;
  373. }
  374.  
  375. - addRow
  376. /*
  377.  *    addRow is implemented by the Matrix superclass as [self insertRowAt:numRows]
  378.  *    so doing all this work here is redundant (and wrong).  Changed this to simply
  379.  *    call super.
  380.  */
  381. {
  382.     int n = [rowSizes count];        /*    copy just to prove a point... */
  383.         
  384.     [super addRow];
  385.     //    to prove my point, look how everything still checks out...
  386.     if (([rowSizes count] != (n+1)) || ((n+1) != numRows)) 
  387.           [self error:"Assertion failed in [MiscMatrix addRow]. Re-implement!"];
  388.  
  389.     return self;
  390. }
  391.  
  392. - insertColAt:(int)col
  393. // Keep the storage in synch
  394. {
  395.     MiscColumnSize newCSize, *cSize;
  396.     
  397.     if ((col < 0) || (col > numCols))
  398.         return nil;
  399.  
  400.     newCSize.width = cellSize.width;
  401.     if (col == 0)                        /* adding first cell ? */
  402.         newCSize.x = bounds.origin.x;
  403.     else 
  404.         if (col == numCols) {            /* adding new last element? */
  405.             cSize = (MiscColumnSize *)[columnSizes lastElement];
  406.             newCSize.x = cSize->x + cSize->width + intercell.width;
  407.         } else {                        /* must be in the middle somewhere... */
  408.             cSize = (MiscColumnSize *)[columnSizes elementAt:col];
  409.             newCSize.x = cSize->x;
  410.         }
  411.  
  412.  
  413.     if (col == numCols)
  414.         [columnSizes addElement:&newCSize];
  415.     else {
  416.         [columnSizes insertElement:&newCSize at:col];
  417.         [self _Misc_moveColumnsRightBy:newCSize.width + intercell.width 
  418.                     startingAt:col+1];
  419.     }
  420.     
  421.     [super insertColAt:col];
  422.  
  423.     return self;
  424. }
  425.  
  426. - insertRowAt:(int)row
  427. // Keep the storage in synch
  428. {
  429.     MiscRowSize newRSize, *rSize;
  430.     
  431.     if ((row < 0) || (row > numRows))
  432.         return nil;
  433.     
  434.     newRSize.height = cellSize.height;
  435.     if (row == 0)                        /* adding first row? */
  436.         newRSize.y = bounds.origin.y;
  437.     else
  438.         if (row == numRows) {            /* adding new last row? */
  439.             rSize = (MiscRowSize *)[rowSizes lastElement];
  440.             newRSize.y = rSize->y + rSize->height + intercell.height;
  441.         } else {                        /* must be in the middle somewhere... */
  442.             rSize = (MiscRowSize *)[rowSizes elementAt:row];
  443.             newRSize.y = rSize->y;
  444.         }
  445.         
  446.  
  447.     if (row == numRows)
  448.         [rowSizes addElement:&newRSize];
  449.     else {
  450.         [rowSizes insertElement:&newRSize at:row];            // changed from row+1 (sq)
  451.         [self _Misc_moveRowsDownBy:newRSize.height + intercell.height 
  452.                 startingAt:row+1];
  453.     }
  454.     
  455.     [super insertRowAt:row];
  456.     
  457.     return self;
  458. }
  459.  
  460. - removeColAt:(int)col andFree:(BOOL)flag
  461. // Keep the storage in synch
  462. {
  463.     MiscColumnSize *cSize;
  464.     NXCoord diff;
  465.     
  466.     if ((col >= numCols) || (col < 0))  {
  467.         return nil;
  468.     }
  469.     
  470.     [super removeColAt:col andFree:flag];
  471.  
  472.     cSize = (MiscColumnSize *)[columnSizes elementAt:col];
  473.     diff = cSize->width;
  474.     [columnSizes removeElementAt:col];
  475.     [self _Misc_moveColumnsRightBy:0.0 - diff - intercell.width    startingAt:col];
  476.     
  477.     return self;
  478. }
  479.  
  480. - removeRowAt:(int)row andFree:(BOOL)flag
  481. // Keep the storage in synch
  482. {
  483.     MiscRowSize *rSize;
  484.     NXCoord diff;
  485.     
  486.     if ((row >= numRows) || (row < 0))  {
  487.         return nil;
  488.     }
  489.  
  490.     [super removeRowAt:row andFree:flag];
  491.  
  492.     rSize = (MiscRowSize *)[rowSizes elementAt:row];
  493.     diff = rSize->height;
  494.     [rowSizes removeElementAt:row];
  495.     [self _Misc_moveRowsDownBy:0.0 - diff - intercell.height startingAt:row];
  496.     
  497.     return self;
  498. }
  499.  
  500. - drawSelf:(const NXRect *)rects:(int)rectCount
  501. // We do our own drawing because we need to draw our cells in diverse 
  502. // rectangles
  503. {
  504.     int row, col;
  505.     int rMin,cMin,rMax,cMax;
  506.     NXPoint lowerRt;
  507.     NXRect cFrm;
  508.     MiscColumnSize *cSize;
  509.     MiscRowSize *rSize;
  510.  
  511. // Scott Violet removed the window flushing stuff; his change in the
  512. // cell rendering should make these unnecessary, so removing them will
  513. // remove flicker when the MiscMatrix is in a SplitView.  I simply
  514. // commented it out for now; --DAY
  515. //    [window disableFlushWindow];
  516.     
  517.     // the background (if any)
  518.     if (backgroundGray != -1.0)  {
  519.         PSsetgray(backgroundGray);
  520.         if (rectCount==1)  {
  521.             NXRectFill(&(rects[0]));
  522.         }  else  {
  523.             NXRectFill(&(rects[1]));
  524.             NXRectFill(&(rects[2]));
  525.         }
  526.     }
  527.     
  528.     /*
  529.      *    calculate the cells that need to be redrawn & iterate through them only...
  530.      */
  531.     [self getRow:&rMin andCol:&cMin forPoint:&(rects->origin)];
  532.     if (rMin == -1)        rMin = 0;
  533.     if (cMin == -1)        cMin = 0;
  534.     
  535.     lowerRt.x = rects->origin.x + rects->size.width;
  536.     lowerRt.y = rects->origin.y + rects->size.height;
  537.     [self getRow:&rMax andCol:&cMax forPoint:&lowerRt];
  538.     if (rMax == -1)        rMax = numRows-1;
  539.     if (cMax == -1)        cMax = numCols-1;
  540.     
  541.     rSize = (MiscRowSize *)[rowSizes elementAt:rMin];
  542.     for (row=rMin; row<=rMax; row++,rSize++)  {
  543.         cSize = (MiscColumnSize *)[columnSizes elementAt:cMin];
  544.         for (col=cMin; col<=cMax; col++,cSize++)  {
  545.             cFrm.origin.x = cSize->x;
  546.             cFrm.origin.y = rSize->y;
  547.             cFrm.size.width = cSize->width;
  548.             cFrm.size.height = rSize->height;
  549.             if (rectCount == 1) {
  550.                 if (NXIntersectsRect(&(rects[0]), &cFrm))
  551.                     // old way: [self drawCellAt:row:col];
  552.                     [self getCellFrame:&cFrm at:row:col];
  553.                     [[self cellAt:row:col] drawInside:&cFrm inView:self];
  554.             } else {
  555.                 if ((NXIntersectsRect(&(rects[1]), &cFrm)) || 
  556.                             (NXIntersectsRect(&(rects[2]), &cFrm)))
  557.                     // old way: [self drawCellAt:row:col];
  558.                     [self getCellFrame:&cFrm at:row:col];
  559.                     [[self cellAt:row:col] drawInside:&cFrm inView:self];
  560.             }
  561.         }
  562.     }
  563.  
  564. //    [window reenableFlushWindow];
  565. //    [window flushWindow];
  566.     
  567.     return self;
  568. }
  569.  
  570. - getCellFrame:(NXRect *)theRect at:(int)row:(int)col
  571. // Calculate and return the rect used to display the cell at the given
  572. // row and column
  573. {
  574.     MiscColumnSize *cSize;
  575.     MiscRowSize *rSize;
  576.     
  577.     if (col < numCols)  {
  578.         cSize = (MiscColumnSize *)[columnSizes elementAt:col];
  579.         theRect->origin.x = cSize->x;
  580.         theRect->size.width = cSize->width;
  581.     }  else  {
  582.         int num = col - numCols;
  583.         
  584.         cSize = (MiscColumnSize *)[columnSizes lastElement];
  585.         theRect->origin.x = cSize->x +
  586.                     (num * (cellSize.width + intercell.width));
  587.         theRect->size.width = cellSize.width;
  588.     }
  589.     
  590.     if (row < numRows)  {
  591.         rSize = (MiscRowSize *)[rowSizes elementAt:row];
  592.         theRect->origin.y = rSize->y;
  593.         theRect->size.height = rSize->height;
  594.     }  else  {
  595.         int num = row - numRows;
  596.         
  597.         rSize = (MiscRowSize *)[rowSizes lastElement];
  598.         theRect->origin.y = rSize->y +
  599.                     (num * (cellSize.height + intercell.height));
  600.         theRect->size.height = cellSize.height;
  601.     }
  602.     
  603.     return self;
  604. }
  605.  
  606. - getRow:(int *)row andCol:(int *)col forPoint:(const NXPoint *)aPoint
  607. // Calculate the row and column of the cell which contains the given point
  608. //    changed to use a bsearch instead of iterative...        - sq
  609. {
  610.     MiscColumnSize *cSize;
  611.     MiscRowSize *rSize;
  612.     int    index, upper, lower;
  613.     
  614.     *row = -1;
  615.     *col = -1;
  616.     if ((aPoint->x < bounds.origin.x) || 
  617.                 (aPoint->x > bounds.origin.x + bounds.size.width) || 
  618.                 (aPoint->y < bounds.origin.y) || 
  619.                 (aPoint->y > bounds.origin.y + bounds.size.height))  {
  620.         return nil;
  621.     }
  622.     cSize = (MiscColumnSize *)[columnSizes elementAt:0];
  623.     lower = 0;
  624.     upper = [columnSizes count];
  625.     while (lower < upper) {
  626.         index = (lower + upper) / 2;
  627.         if (aPoint->x < cSize[index].x)
  628.             upper = index;                    // lower, look to the left...
  629.         else if (aPoint->x > (cSize[index].x + cSize[index].width))
  630.             lower = index + 1;                // higher, look to the right...
  631.         else {
  632.             *col = index;                    // hit it...
  633.             break;
  634.         }
  635.     }
  636.     rSize = (MiscRowSize *)[rowSizes elementAt:0];
  637.     lower = 0;
  638.     upper = [rowSizes count];
  639.     while (lower < upper) {
  640.         index = (lower + upper) / 2;
  641.         if (aPoint->y < rSize[index].y)
  642.             upper = index;                    // lower, look to the left...
  643.         else if (aPoint->y > (rSize[index].y + rSize[index].height))
  644.             lower = index + 1;                // higher, look to the right...
  645.         else {
  646.             *row = index;                    // hit it...
  647.             break;
  648.         }
  649.     }
  650.     return ((*row == -1) || (*col == -1)) ? nil : self;
  651. }
  652.  
  653. - setIntercell:(const NXSize *)aSize
  654. // Keep the storage in synch
  655. {
  656.     NXCoord xDiff = aSize->width - intercell.width;
  657.     NXCoord yDiff = aSize->height - intercell.height;
  658.     MiscRowSize *rSize;
  659.     MiscColumnSize *cSize;
  660.     int i;
  661.     
  662.     for (i=1; i<numRows; i++)  {
  663.         rSize = (MiscRowSize *)[rowSizes elementAt:i];
  664.         rSize->y += (yDiff * i);
  665.     }
  666.     for (i=1; i<numCols; i++)  {
  667.         cSize = (MiscColumnSize *)[columnSizes elementAt:i];
  668.         cSize->x += (xDiff * i);
  669.     }
  670.     
  671.     return [super setIntercell:aSize];
  672. }
  673.  
  674.  
  675. - write:(NXTypedStream *)typedStream
  676. // Write our ivars
  677. {
  678.     [super write:typedStream];
  679.     NXWriteObject(typedStream, columnSizes);
  680.     NXWriteObject(typedStream, rowSizes);
  681.     return self;
  682. }
  683.  
  684. - read:(NXTypedStream *)typedStream
  685. // Read our ivars
  686. {
  687.     int classVersion;
  688.  
  689.     [super read:typedStream];
  690.     
  691.     classVersion = NXTypedStreamClassVersion(typedStream, CLASS_NAME);
  692.     
  693.     switch (classVersion)  {
  694.         case 0:        // First version.
  695.             columnSizes = NXReadObject(typedStream);
  696.             rowSizes = NXReadObject(typedStream);
  697.             break;
  698.         default:
  699.             NXLogError("[%s read:] class version %d cannot read "
  700.                         "instances archived with version %d", 
  701.                         CLASS_NAME, CLASS_VERSION, classVersion);
  702.             [self setupStorage:numRows :numCols];
  703.             break;
  704.     }
  705.     return self;
  706. }
  707.  
  708.  
  709. // ********************Overridden private methods***********************
  710. // *****************that I'm going to hell for using********************
  711.  
  712. // These methods are used by Matrix's mouseDown:.  Doing the whole 
  713. // mouseDown: method over would have been a royal pain in the butt, 
  714. // so I cheated.
  715.  
  716.  
  717. - (BOOL)_mouseHit:(const NXPoint *)forpoint row:(int *)row col:(int *)col
  718. {
  719.     NXPoint    point;
  720.     id        ret;
  721.  
  722.     point = *forpoint;
  723.     [self convertPoint:&point fromView:nil];
  724.     ret = [self getRow:row andCol:col forPoint:&point];
  725.  
  726.     if (ret == nil)
  727.         return NO;
  728.     return YES;
  729. }
  730.  
  731. - (BOOL)_loopHit:(const NXPoint *)forpoint row:(int *)row col:(int *)col
  732. {
  733.     NXPoint    point;
  734.     id        ret;
  735.  
  736.     point = *forpoint;
  737.     [self convertPoint:&point fromView:nil];
  738.     ret = [self getRow:row andCol:col forPoint:&point];
  739.  
  740.     if (ret == nil)
  741.         return NO;
  742.     return YES;
  743. }
  744.  
  745. - (BOOL)_radioHit:(const NXPoint *)forpoint row:(int *)row col:(int *)col
  746. {
  747.     NXPoint    point;
  748.     id        ret;
  749.  
  750.     point = *forpoint;
  751.     [self convertPoint:&point fromView:nil];
  752.     ret = [self getRow:row andCol:col forPoint:&point];
  753.  
  754.     if (ret == nil)
  755.         return NO;
  756.     return YES;
  757. }
  758.  
  759. - sizeRowsToFitCells
  760. {
  761.     NXRect    veryBig;
  762.     NXSize    size;
  763.     NXRect    myFrame;
  764.     NXCoord    maxHeight;
  765.     NXCoord    offset = 0.0;
  766.     MiscRowSize    *rSize;
  767.     int        i,j;
  768.     
  769.     veryBig.size.width = cellSize.width;
  770.     veryBig.size.height = MAXFLOAT;
  771.     
  772.     [self getFrame:&myFrame];
  773.     for (i = 0; i < numRows; i++)
  774.     {
  775.     maxHeight = 0.0;
  776.     rSize = (MiscRowSize *)[rowSizes elementAt:i];
  777.     rSize->y = offset;
  778.     for (j = 0; j < numCols; j++)
  779.     {
  780.         [[self cellAt:i :j] calcCellSize:&size inRect:&veryBig];
  781.         if (size.height > maxHeight)
  782.         maxHeight = size.height;
  783.     }
  784.     rSize->height = maxHeight;
  785.     offset += maxHeight + intercell.height;
  786.     }
  787.     
  788.     myFrame.size.height = offset;
  789.     // This can't be used:  [self setFrame:&myFrame];
  790.     /*
  791.      * We can't call setFrame: here because it will call sizeTo::
  792.      * which will try to modify cellFrame and the column/row sizes.
  793.      * So we just copy into the instance variable.
  794.      *
  795.      * And we'll probably be sent to the deepest corners of hell for doing it.
  796.      */   
  797.     // frame = myFrame;
  798.     // This has been suggested as a perhaps safer way to do the same thing,
  799.     // so we'll use it instead of the above line, but I'm keeping the above
  800.     // until we are sure that it is doing the right thing...  -DAY
  801.     /*
  802.      * We use super here to avoid re-adjusting the row
  803.      * and column sizes.
  804.      */
  805.     [super sizeTo:myFrame.size.width :myFrame.size.height];  
  806.       
  807.     return self;
  808. }
  809.     
  810.  
  811. - sizeTo:(NXCoord)width :(NXCoord)height
  812. {
  813.     NXRect    oldFrame;
  814.     NXCoord    dx, dy;
  815.     float    sx, sy;
  816.     
  817.     [self getFrame:&oldFrame];
  818.     
  819.     [super sizeTo:width :height];
  820.  
  821.     dx = width - oldFrame.size.width;
  822.     dy = height - oldFrame.size.height;
  823.  
  824.     if ([self doesAutosizeCells] && (numRows > 0) && (numCols > 0))
  825.     {
  826.     NXCoord        offset;
  827.     int        i;
  828.     MiscRowSize    *rSize;
  829.     MiscColumnSize    *cSize;
  830.     
  831.     sx = 1 + (dx/(oldFrame.size.width - (numRows - 1)*intercell.width));
  832.     sy = 1 + (dy/(oldFrame.size.height - (numCols - 1)*intercell.height));
  833.     
  834.     for (i=0, offset = 0.0; i < numRows; i++)
  835.     {
  836.         rSize = (MiscRowSize *)[rowSizes elementAt:i];
  837.         rSize->y = offset;
  838.         rSize->height *= floor(sy+0.5);
  839.         offset += rSize->height + intercell.height;
  840.     }
  841.     
  842.     for (i=0, offset = 0.0; i < numCols; i++)
  843.     {
  844.         cSize = (MiscColumnSize *)[columnSizes elementAt:i];
  845.         cSize->x = offset;
  846.         cSize->width *= sx;
  847.         offset += cSize->width + intercell.width;
  848.     }
  849.     }
  850.     return self;
  851. }
  852.  
  853. @end
  854.  
  855. @implementation Storage(MiscLastElementCategory)
  856.     
  857. - (void *)lastElement
  858. // A little shortcut
  859. {
  860.     void *theLastOne;
  861.     theLastOne = (numElements) ? (char *)dataPtr + (elementSize*(numElements-1)) : NULL;
  862.     return theLastOne;
  863. }
  864.     
  865. @end
  866.  
  867.