home *** CD-ROM | disk | FTP | other *** search
- //
- // MiscMatrix.m -- a class to implement variable-sized matrices
- // Written by Mike Ferris (c) 1994 by Mike Ferris.
- // Modified from original MOKit "MOMatrix" class by Don Yacktman.
- // Version 1.0. All rights reserved.
- //
- // This notice may not be removed from this source code.
- //
- // This object is included in the MiscKit by permission from the author
- // and its use is governed by the MiscKit license, found in the file
- // "LICENSE.rtf" in the MiscKit distribution. Please refer to that file
- // for a list of all applicable permissions and restrictions.
- //
-
- // MiscMatrix is a subclass of Matrix that allows independantly sizable
- // rows and columns. Each row can have a different height and each column
- // can have a different width.
-
- #import <misckit/MiscMatrix.h>
- #import <objc/objc-runtime.h>
-
- #define CLASS_VERSION 0
- #define CLASS_NAME "MiscMatrix"
-
- // These are the private methods we use in MiscMatrix
- @interface MiscMatrix(private)
-
- - _Misc_copyRowSizes:rs andColSizes:cs zone:(NXZone *)zone;
- - _Misc_moveColumnsRightBy:(NXCoord)difference startingAt:(int)col;
- - _Misc_moveRowsDownBy:(NXCoord)difference startingAt:(int)row;
-
- @end
-
- @implementation MiscMatrix
-
- + initialize
- // Set the class version
- {
- if (self == objc_lookUpClass(CLASS_NAME)) {
- [self setVersion:CLASS_VERSION];
- }
- return self;
- }
-
- - setupStorage:(int)rowsHigh :(int)colsWide
- // Set up our storage objects
- {
- int i;
- MiscColumnSize newCSize;
- MiscRowSize newRSize;
-
- columnSizes = [[Storage allocFromZone:[self zone]] initCount:0
- elementSize:sizeof(MiscColumnSize)
- description:MISC_COLUMNSIZE_DESC];
- rowSizes = [[Storage allocFromZone:[self zone]] initCount:0
- elementSize:sizeof(MiscRowSize)
- description:MISC_ROWSIZE_DESC];
-
- newCSize.width = cellSize.width;
- newRSize.height = cellSize.height;
- for (i=0; i<colsWide; i++) {
- newCSize.x = bounds.origin.x + (i*cellSize.width) +
- (i*intercell.width);
- [columnSizes addElement:&newCSize];
- }
- for (i=0; i<rowsHigh; i++) {
- newRSize.y = bounds.origin.y + (i*cellSize.height) +
- (i*intercell.height);
- [rowSizes addElement:&newRSize];
- }
-
- return self;
- }
-
- - initFrame:(const NXRect *)frm mode:(int)aMode prototype:cellId
- numRows:(int)rowsHigh numCols:(int)colsWide
- // Designated initializer override from Matrix. Sets up our storage stuff.
- {
- [super initFrame:frm mode:aMode prototype:cellId numRows:numRows
- numCols:numCols];
-
- [self setupStorage:rowsHigh :colsWide];
-
- return self;
- }
-
- - initFrame:(const NXRect *)frm mode:(int)aMode cellClass:factoryId
- numRows:(int)rowsHigh numCols:(int)colsWide
- // Designated initializer override from Matrix. Sets up our storage stuff.
- {
- [super initFrame:frm mode:aMode cellClass:factoryId numRows:numRows
- numCols:numCols];
-
- [self setupStorage:rowsHigh :colsWide];
-
- return self;
- }
-
- - _Misc_copyRowSizes:rs andColSizes:cs zone:(NXZone *)zone
- {
- rowSizes = [rs copyFromZone:zone];
- columnSizes = [cs copyFromZone:zone];
- return self;
- }
-
- - copyFromZone:(NXZone *)zone
- {
- id obj = [super copyFromZone:zone];
- [obj _Misc_copyRowSizes:rowSizes andColSizes:columnSizes zone:zone];
- return obj;
- }
-
- - free
- // free the storage
- {
- [columnSizes free];
- [rowSizes free];
- return [super free];
- }
-
- - _Misc_moveColumnsRightBy:(NXCoord)difference startingAt:(int)col
- // A private method used by the methods which cause sizing stuff to change
- {
- int i;
-
- if ((col < 0) || (col >= numCols)) {
- return nil;
- }
-
- for (i=col; i<numCols; i++) {
- MiscColumnSize *cSize;
- cSize = (MiscColumnSize *)[columnSizes elementAt:i];
- if (cSize) cSize->x += difference;
- }
- return self;
- }
-
- - _Misc_moveRowsDownBy:(NXCoord)difference startingAt:(int)row
- // A private method used by the methods which cause sizing stuff to change
- {
- int i;
-
- if ((row < 0) || (row >= numRows)) {
- return nil;
- }
-
- for (i=row; i<numRows; i++) {
- MiscRowSize *rSize;
- rSize = (MiscRowSize *)[rowSizes elementAt:i];
- if (rSize) rSize->y += difference;
- }
- return self;
- }
-
- - setWidth:(NXCoord)newWidth ofCol:(int)col
- // This method allows the setting of column widths
- {
- NXCoord diff;
- MiscColumnSize *cSize;
-
- if ((col < 0) || (col >= numCols)) {
- return nil;
- }
-
- cSize = (MiscColumnSize *)[columnSizes elementAt:col];
- diff = newWidth - cSize->width;
- cSize->width = newWidth;
- [self _Misc_moveColumnsRightBy:diff startingAt:col+1];
-
- return self;
- }
-
- - setHeight:(NXCoord)newHeight ofRow:(int)row
- // This method allows the setting of row heights
- {
- NXCoord diff;
- MiscRowSize *rSize;
-
- if ((row < 0) || (row >= numRows)) {
- return nil;
- }
-
- rSize = (MiscRowSize *)[rowSizes elementAt:row];
- diff = newHeight - rSize->height;
- rSize->height = newHeight;
- [self _Misc_moveRowsDownBy:diff startingAt:row+1];
-
- return self;
- }
-
- - sizeToCells
- // Resize the matrix to the proper size to fit all our cells.
- {
- NXRect rect;
- MiscColumnSize *cSize;
- MiscRowSize *rSize;
-
- [self getFrame:&rect];
-
- if (numCols == 0) {
- rect.size.width = 0.0;
- } else {
- cSize = (MiscColumnSize *)[columnSizes lastElement];
- rect.size.width = cSize->x + cSize->width - bounds.origin.x;
- }
-
- if (numRows == 0) {
- rect.size.height = 0.0;
- } else {
- rSize = (MiscRowSize *)[rowSizes lastElement];
- rect.size.height = rSize->y + rSize->height - bounds.origin.y;
- }
-
- [self setFrame:&rect];
-
- return self;
- }
-
- - renewRows:(int)newRows cols:(int)newCols
- // Makes sure to keep our storage objects in synch with everything else.
- {
- MiscColumnSize newCSize, *cSize;
- MiscRowSize newRSize, *rSize;
- int i;
-
- // Remove any storage elements past the new number of cols
- for (i=numCols-1; i>=newCols; i--) {
- [columnSizes removeLastElement];
- }
- // Add any needed new storage elements to get up to the new number of cols
- for (i=numCols; i<newCols; i++) {
- if (i==0) {
- newCSize.x = bounds.origin.x;
- } else {
- cSize = (MiscColumnSize *)[columnSizes lastElement];
- newCSize.x = cSize->x + cSize->width + intercell.width;
- }
- newCSize.width = cellSize.width;
- [columnSizes addElement:&newCSize];
- }
-
- // Remove any storage elements past the new number of rows
- for (i=numRows-1; i>=newRows; i++) {
- [rowSizes removeLastElement];
- }
- // Add any needed new storage elements to get up to the new number of rows
- for (i=numRows; i<newRows; i++) {
- if (i==0) {
- newRSize.y = bounds.origin.y;
- } else {
- rSize = (MiscRowSize *)[rowSizes lastElement];
- newRSize.y = rSize->y + rSize->height + intercell.height;
- }
- newRSize.height = cellSize.height;
- [rowSizes addElement:&newRSize];
- }
-
- [super renewRows:newRows cols:newCols];
-
- return self;
- }
-
- - addCol
- // Keep the storage in synch
- {
- MiscColumnSize newCSize, *cSize;
-
- [super addCol];
-
- if (numCols > 0) {
- cSize = (MiscColumnSize *)[columnSizes lastElement];
- newCSize.x = cSize->x + cSize->width + intercell.width;
- } else {
- newCSize.x = bounds.origin.x;
- }
- newCSize.width = cellSize.width;
- [columnSizes addElement:&newCSize];
-
- return self;
- }
-
- - addRow
- // Keep the storage in synch
- {
- MiscRowSize newRSize, *rSize;
-
- [super addRow];
-
- if (numRows > 0) {
- rSize = (MiscRowSize *)[rowSizes lastElement];
- newRSize.y = rSize->y + rSize->height + intercell.height;
- } else {
- newRSize.y = bounds.origin.y;
- }
- newRSize.height = cellSize.height;
- [rowSizes addElement:&newRSize];
-
- return self;
- }
-
- - insertColAt:(int)col
- // Keep the storage in synch
- {
- MiscColumnSize newCSize, *cSize;
-
- if (col < 0) {
- return nil;
- }
-
- if (col <= numCols) {
- [super insertColAt:col];
-
- if (col > 0) {
- cSize = (MiscColumnSize *)[columnSizes elementAt:col];
- newCSize.x = cSize->x;
- } else {
- newCSize.x = bounds.origin.x;
- }
- newCSize.width = cellSize.width;
- [columnSizes insertElement:&newCSize at:col];
-
- [self _Misc_moveColumnsRightBy:newCSize.width + intercell.width
- startingAt:col+1];
- } else {
- return nil;
- }
- return self;
- }
-
- - insertRowAt:(int)row
- // Keep the storage in synch
- {
- MiscRowSize newRSize, *rSize;
-
- if (row < 0) {
- return nil;
- }
-
- if (row <= numRows) {
- [super insertRowAt:row];
-
- if (row > 0) {
- rSize = (MiscRowSize *)[rowSizes elementAt:row];
- newRSize.y = rSize->y;
- } else {
- newRSize.y = bounds.origin.y;
- }
- newRSize.height = cellSize.height;
- [rowSizes insertElement:&newRSize at:row+1];
-
- [self _Misc_moveRowsDownBy:newRSize.height + intercell.height
- startingAt:row+1];
- } else {
- return nil;
- }
- return self;
- }
-
- - removeColAt:(int)col andFree:(BOOL)flag
- // Keep the storage in synch
- {
- MiscColumnSize *cSize;
- NXCoord diff;
-
- if ((col >= numCols) || (col < 0)) {
- return nil;
- }
-
- [super removeColAt:col andFree:flag];
-
- cSize = (MiscColumnSize *)[columnSizes elementAt:col];
- diff = cSize->width;
- [columnSizes removeElementAt:col];
- [self _Misc_moveColumnsRightBy:0.0 - diff - intercell.width
- startingAt:col];
-
- return self;
- }
-
- - removeRowAt:(int)row andFree:(BOOL)flag
- // Keep the storage in synch
- {
- MiscRowSize *rSize;
- NXCoord diff;
-
- if ((row >= numRows) || (row < 0)) {
- return nil;
- }
-
- [super removeRowAt:row andFree:flag];
-
- rSize = (MiscRowSize *)[rowSizes elementAt:row];
- diff = rSize->height;
- [rowSizes removeElementAt:row];
- [self _Misc_moveRowsDownBy:0.0 - diff - intercell.height startingAt:row];
-
- return self;
- }
-
- - drawSelf:(const NXRect *)rects:(int)rectCount
- // We do our own drawing because we need to draw our cells in diverse
- // rectangles
- {
- int i, j;
- NXRect cFrm;
-
- [window disableFlushWindow];
-
- // the background (if any)
- if (backgroundGray != -1.0) {
- PSsetgray(backgroundGray);
- if (rectCount==1) {
- NXRectFill(&(rects[0]));
- } else {
- NXRectFill(&(rects[1]));
- NXRectFill(&(rects[2]));
- }
- }
-
- // The cells
- for (i=0; i<numRows; i++) {
- for (j=0; j<numCols; j++) {
- [self getCellFrame:&cFrm at:i:j];
- if (rectCount == 1) {
- if (NXIntersectsRect(&(rects[0]), &cFrm)) {
- [self drawCellAt:i:j];
- }
- } else {
- if ((NXIntersectsRect(&(rects[1]), &cFrm)) ||
- (NXIntersectsRect(&(rects[2]), &cFrm))) {
- [self drawCellAt:i:j];
- }
- }
- }
- }
-
- [window reenableFlushWindow];
- [window flushWindow];
-
- return self;
- }
-
- - getCellFrame:(NXRect *)theRect at:(int)row:(int)col
- // Calculate and return the rect used to display the cell at the given
- // row and column
- {
- MiscColumnSize *cSize;
- MiscRowSize *rSize;
-
- if (col < numCols) {
- cSize = (MiscColumnSize *)[columnSizes elementAt:col];
- theRect->origin.x = cSize->x;
- theRect->size.width = cSize->width;
- } else {
- int num = col - numCols;
-
- cSize = (MiscColumnSize *)[columnSizes lastElement];
- theRect->origin.x = cSize->x +
- (num * (cellSize.width + intercell.width));
- theRect->size.width = cellSize.width;
- }
-
- if (row < numRows) {
- rSize = (MiscRowSize *)[rowSizes elementAt:row];
- theRect->origin.y = rSize->y;
- theRect->size.height = rSize->height;
- } else {
- int num = row - numRows;
-
- rSize = (MiscRowSize *)[rowSizes lastElement];
- theRect->origin.y = rSize->y +
- (num * (cellSize.height + intercell.height));
- theRect->size.height = cellSize.height;
- }
-
- return self;
- }
-
- - getRow:(int *)row andCol:(int *)col forPoint:(const NXPoint *)aPoint
- // Calculate the row and column of the cell which contains the given point
- {
- MiscColumnSize *cSize;
- MiscRowSize *rSize;
- int i;
-
- *row = -1;
- *col = -1;
- if ((aPoint->x < bounds.origin.x) ||
- (aPoint->x > bounds.origin.x + bounds.size.width) ||
- (aPoint->y < bounds.origin.y) ||
- (aPoint->y > bounds.origin.y + bounds.size.height)) {
- return self;
- }
- for (i=0; i<numCols; i++) {
- cSize = (MiscColumnSize *)[columnSizes elementAt:i];
- if ((aPoint->x >= cSize->x) &&
- (aPoint->x <= cSize->x + cSize->width)) {
- *col = i;
- break;
- }
- }
- for (i=0; i<numRows; i++) {
- rSize = (MiscRowSize *)[rowSizes elementAt:i];
- if ((aPoint->y >= rSize->y) &&
- (aPoint->y <= rSize->y + rSize->height)) {
- *row = i;
- break;
- }
- }
- return self;
- }
-
- - setIntercell:(const NXSize *)aSize
- // Keep the storage in synch
- {
- NXCoord xDiff = aSize->width - intercell.width;
- NXCoord yDiff = aSize->height - intercell.height;
- MiscRowSize *rSize;
- MiscColumnSize *cSize;
- int i;
-
- for (i=1; i<numRows; i++) {
- rSize = (MiscRowSize *)[rowSizes elementAt:i];
- rSize->y += (yDiff * i);
- }
- for (i=1; i<numCols; i++) {
- cSize = (MiscColumnSize *)[columnSizes elementAt:i];
- cSize->x += (xDiff * i);
- }
-
- return [super setIntercell:aSize];
- }
-
-
- - write:(NXTypedStream *)typedStream
- // Write our ivars
- {
- [super write:typedStream];
- NXWriteObject(typedStream, columnSizes);
- NXWriteObject(typedStream, rowSizes);
- return self;
- }
-
- - read:(NXTypedStream *)typedStream
- // Read our ivars
- {
- int classVersion;
-
- [super read:typedStream];
-
- classVersion = NXTypedStreamClassVersion(typedStream, CLASS_NAME);
-
- switch (classVersion) {
- case 0: // First version.
- columnSizes = NXReadObject(typedStream);
- rowSizes = NXReadObject(typedStream);
- break;
- default:
- NXLogError("[%s read:] class version %d cannot read "
- "instances archived with version %d",
- CLASS_NAME, CLASS_VERSION, classVersion);
- [self setupStorage:numRows :numCols];
- break;
- }
- return self;
- }
-
-
- // ********************Overridden private methods***********************
- // *****************that I'm going to hell for using********************
-
- // These methods are used by Matrix's mouseDown:. Doing the whole
- // mouseDown: method over would have been a royal pain in the butt,
- // so I cheated.
-
-
- - (BOOL)_mouseHit:(const NXPoint *)forpoint row:(int *)row col:(int *)col
- {
- NXPoint point;
- id ret;
-
- point = *forpoint;
- [self convertPoint:&point fromView:nil];
- ret = [self getRow:row andCol:col forPoint:&point];
-
- if (ret == nil)
- return NO;
- return YES;
- }
-
- - (BOOL)_loopHit:(const NXPoint *)forpoint row:(int *)row col:(int *)col
- {
- NXPoint point;
- id ret;
-
- point = *forpoint;
- [self convertPoint:&point fromView:nil];
- ret = [self getRow:row andCol:col forPoint:&point];
-
- if (ret == nil)
- return NO;
- return YES;
- }
-
- - (BOOL)_radioHit:(const NXPoint *)forpoint row:(int *)row col:(int *)col
- {
- NXPoint point;
- id ret;
-
- point = *forpoint;
- [self convertPoint:&point fromView:nil];
- ret = [self getRow:row andCol:col forPoint:&point];
-
- if (ret == nil)
- return NO;
- return YES;
- }
-
-
- @end
-
- @implementation Storage(MiscLastElementCategory)
-
- - (void *)lastElement
- // A little shortcut
- {
- return [self elementAt:numElements-1];
- }
-
- @end
-
-