/* NSMatrix.m Matrix class for grouping controls Copyright (C) 1996 Free Software Foundation, Inc. Author: Pascal Forget Scott Christley Date: 1996 This file is part of the GNUstep GUI Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. If you are interested in a warranty or support for this source code, contact Scott Christley for more information. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #define GNU_DEFAULT_CELL_HEIGHT 20 // // Class variables // Class NSMATRIX_DEFAULT_CELL_CLASS; @implementation NSMatrix + (void)initialize { if (self == [NSMatrix class]) { NSDebugLog(@"Initialize NSMatrix class\n"); // Set initial version [self setVersion: 1]; } } // // Initializing the NSMatrix Class // + (Class)cellClass { return NSMATRIX_DEFAULT_CELL_CLASS; } + (void)setCellClass:(Class)classId { NSMATRIX_DEFAULT_CELL_CLASS = classId; } // // Initializing an NSMatrix Object // - (void)createInitialMatrix { NSSize cs; int i, j; id aRow, aFloat; // Determine cell width and height for uniform cell size cs.width = (frame.size.width - (inter_cell.width * (num_cols - 1))) / num_cols; cs.height = (frame.size.height - (inter_cell.height * (num_rows - 1))) / num_rows; // Save cell widths and heights in arrays aFloat = [NSNumber numberWithFloat: cs.height]; for (i = 0;i < num_rows; ++i) [row_heights addObject:aFloat]; aFloat = [NSNumber numberWithFloat: cs.width]; for (i = 0;i < num_cols; ++i) [col_widths addObject:aFloat]; for (i = 0;i < num_rows; ++i) { aRow = [NSMutableArray arrayWithCapacity: j]; [rows addObject: aRow]; for (j = 0;j < num_cols; ++j) { if (cell_prototype != nil) { [(NSMutableArray *)aRow addObject: [cell_prototype copy]]; } else { [(NSMutableArray *)aRow addObject: [[cell_class alloc] init]]; } } } } - (id)initWithFrame:(NSRect)frameRect { return [self initWithFrame:frameRect mode:NSTrackModeMatrix cellClass:[NSCell class] numberOfRows:0 numberOfColumns:0]; } - (id)initWithFrame:(NSRect)frameRect mode:(int)aMode cellClass:(Class)classId numberOfRows:(int)rowsHigh numberOfColumns:(int)colsWide { NSDebugLog(@"NSMatrix start -initWithFrame: ..cellClass:\n"); [super initWithFrame:frameRect]; if (rowsHigh < 0) { NSLog(@"NSMatrix initWithFrame:mode: rows has to be >= 0.\n"); NSLog(@"Will create matrix with 0 rows.\n"); num_rows = 0; } else { num_rows = rowsHigh; } if (colsWide < 0) { NSLog(@"NSMatrix initWithFrame:mode: columns has to be >= 0.\n"); NSLog(@"Will create matrix with 0 columns.\n"); num_cols = 0; } else { num_cols = colsWide; } rows = [[NSMutableArray alloc] init]; row_heights = [[NSMutableArray alloc] init]; col_widths = [[NSMutableArray alloc] init]; selected_cells = [[NSMutableArray alloc] init]; inter_cell.width = inter_cell.height = 2; cell_prototype = nil; cell_class = classId; mode = aMode; [self createInitialMatrix]; NSDebugLog(@"NSMatrix end -initWithFrame: ..cellClass:\n"); return self; } - (id)initWithFrame:(NSRect)frameRect mode:(int)aMode prototype:(NSCell *)aCell numberOfRows:(int)rowsHigh numberOfColumns:(int)colsWide { [super initWithFrame:frameRect]; if (aCell == nil) { NSLog(@"NSMatrix "); NSLog(@"initWithFrame:mode:prototype:numberOfRows:numberOfColumns: "); NSLog(@"prototype can't be nil. "); NSLog(@"Using NSCell as the default class.\n"); cell_prototype = nil; cell_class = [NSCell class]; } else { cell_prototype = [aCell retain]; } return self; } // // Setting the Selection Mode // - (NSMatrixMode)mode { return mode; } - (void)setMode:(NSMatrixMode)aMode { mode = aMode; } // // Configuring the NSMatrix // - (BOOL)allowsEmptySelection { return allows_empty_selection; } - (BOOL)isSelectionByRect { return selection_by_rect; } - (void)setAllowsEmptySelection:(BOOL)flag { allows_empty_selection = flag; } - (void)setSelectionByRect:(BOOL)flag { selection_by_rect = flag; } // // Setting the Cell Class // - (Class)cellClass { return cell_class; } - (id)prototype { return cell_prototype; } - (void)setCellClass:(Class)classId { cell_class = classId; } - (void)setPrototype:(NSCell *)aCell { cell_prototype = [aCell retain]; } // // Laying Out the NSMatrix // - (void)addColumn { int i; NSNumber *anInt; NSMutableArray *aRow; if (num_rows <= 0) { [rows addObject:[[NSMutableArray alloc] init]]; num_rows = 1; [row_heights removeAllObjects]; anInt = [NSNumber numberWithInt: GNU_DEFAULT_CELL_HEIGHT]; [row_heights addObject:anInt]; } for (i=0; i 0) { for (i=1; i= num_rows) || (row < 0)) { return r; } if ((column >= num_cols) || (column < 0)) { return r; } /* Compute the x origin */ for (i=0; i 1) { for (i=0; icolumn; j--) { [currentRow replaceObjectAtIndex:j withObject: [currentRow objectAtIndex:i-1]]; } [currentRow replaceObjectAtIndex:column withObject:newCell]; } } } - (void)insertColumn:(int)column withCells:(NSArray *)cellArray { NSCell *newCell; int i, count; [self insertColumn:column]; if (cellArray != nil) { count = [cellArray count]; } else { count = 0; } for (i=0; i 1) { aRow = [rows lastObject]; for (i=num_rows-1; i> row; i--) { [rows replaceObjectAtIndex:i withObject:[rows objectAtIndex:i-1]]; } [rows replaceObjectAtIndex:row withObject:aRow]; } } - (void)insertRow:(int)row withCells:(NSArray *)cellArray { NSCell *newCell; int i, count; [self insertRow:row]; if (cellArray != nil) { count = [cellArray count]; } else { count = 0; } for (i=0; i -1) && (column < num_cols) && (column > -1)) { newCell = [[cell_class alloc] init]; [[rows objectAtIndex:row] replaceObjectAtIndex:column withObject:newCell]; return newCell; } else { return nil; } } - (void)putCell:(NSCell *)newCell atRow:(int)row column:(int)column { NSMutableArray *aRow; if ((row > -1) && (row < num_rows) && (column > -1) && (column < num_cols)) { aRow = (NSMutableArray *)[rows objectAtIndex:row]; [aRow replaceObjectAtIndex:column withObject:newCell]; } } - (void)removeColumn:(int)column { int i; NSMutableArray *aRow; if ((column > -1) && (column < num_cols)) { for (i=0; i -1) && (row < num_rows)) { [rows removeObjectAtIndex:row]; [row_heights removeObjectAtIndex:row]; num_rows--; } } - empty { [rows removeAllObjects]; [selected_cells removeAllObjects]; num_rows = 0; num_cols = 0; return self; } - (void)renewRows:(int)newRows columns:(int)newColumns {} - (void)setCellSize:(NSSize)aSize { NSNumber *aFloat; id old; int i; for (i=0; i -1) && (column < num_cols)) { aFloat = [NSNumber numberWithFloat: width]; old = [col_widths objectAtIndex:column]; [col_widths replaceObjectAtIndex:column withObject: aFloat]; [old release]; } } - (void)setIntercellSpacing:(NSSize)aSize { inter_cell = aSize; } - (void)sortUsingFunction:(int (*)(id element1, id element2, void *userData))comparator context:(void *)context {} - (void)sortUsingSelector:(SEL)comparator {} - (int)numCols; { return num_cols; } - (int)numRows; { return num_rows; } // // Finding Matrix Coordinates // /* * The next function returns NO if the point is located inside * the matrix but also in an intercell gap, which may or may * not be the behavior God intended... */ - (BOOL)getRow:(int *)row column:(int *)column forPoint:(NSPoint)aPoint { NSRect myFrame = [self bounds]; NSRect cFrame; int i, j; /* Trivial rejection if the point is not in the Matrix's frame rect */ if ((aPoint.x < myFrame.origin.x) || (aPoint.x > (myFrame.origin.x + myFrame.size.width)) || (aPoint.y < myFrame.origin.y) || (aPoint.y > (myFrame.origin.y + myFrame.size.height))) { NSDebugLog(@"NSMatrix not in frame rect\n"); return NO; } else { /* Here an optimized algo could be used at the expense of clarity */ for (i=0; i= cFrame.origin.x) && (aPoint.x <= (cFrame.origin.x + cFrame.size.width)) && (aPoint.y >= cFrame.origin.y) && (aPoint.y <= (cFrame.origin.y + cFrame.size.height))) { *row = i; *column = j; return YES; } } } return NO; } } - (BOOL)getRow:(int *)row column:(int *)column ofCell:(NSCell *)aCell { int i, j; for (i=0; i -1) && (row < num_rows) && (column > -1) && (column < num_cols)) { aRow = (NSMutableArray *)[rows objectAtIndex:row]; aCell = (NSCell *)[aRow objectAtIndex:column]; [aCell setState:value]; } } // // Selecting Cells // - (void)deselectAllCells { [selected_cells removeAllObjects]; } - (void)deselectSelectedCell { [selected_cells removeLastObject]; } - (void)selectAll:(id)sender { [selected_cells removeAllObjects]; [selected_cells addObjectsFromArray:[self cells]]; } - (void)selectCellAtRow:(int)row column:(int)column { int index; id aCell = [self cellAtRow:row column:column]; NSDebugLog(@"NSMatrix select cell at %d %d\n", row, column); if (aCell != nil) { index = [selected_cells indexOfObject:aCell]; if ((index < 0) || (index > [selected_cells count])) { [selected_cells addObject:aCell]; } } } - (BOOL)selectCellWithTag:(int)anInt { id aCell = [self cellWithTag:anInt]; int index; if (cell != nil) { index = [selected_cells indexOfObject:aCell]; if ((index < 0) || (index > [selected_cells count])) { [selected_cells addObject:aCell]; } return YES; } else { return NO; } } - (id)selectedCell { return [selected_cells lastObject]; } /* * returns an array of the selected cells */ - (NSArray *)selectedCells { return selected_cells; } - (int)selectedColumn { int row, col; NSMutableArray *aRow, *aCol; id aCell; if ([selected_cells count]) { aCell = [selected_cells lastObject]; for (row=0; row 0) { aCell = [selected_cells lastObject]; for (row=0; row= num_rows) || (row < 0)) { NSLog(@"NSMatrix cellAt:: invalid row (%d)\n", row); return nil; } if ((column >= num_cols) || (column < 0)) { NSLog(@"NSMatrix cellAt:: invalid column (%d)\n", column); return nil; } return [(NSArray *)[rows objectAtIndex:row] objectAtIndex:column]; } - (id)cellWithTag:(int)anInt { int i, j; NSMutableArray *aRow; NSCell *aCell; for (i=0; i 0) && (row < (num_rows-1) )) { newSize.height += inter_cell.height; } } for (col=0; col 0) && (col < (num_cols-1) )) { newSize.width += inter_cell.width; } } #if 1 NSLog(@"NSMatrix size: %4.0f %4.0f\n",newSize.width,newSize.height); #endif [(NSView *)self setFrameSize:newSize]; } // // Scrolling // - (BOOL)isAutoscroll { return autoscroll; } - (void)scrollCellToVisibleAtRow:(int)row column:(int)column {} - (void)setAutoscroll:(BOOL)flag { autoscroll = flag; } - (void)setScrollable:(BOOL)flag { scrollable = flag; } // // Displaying // - (void)display; { int row,col; int rcnt, ccnt; NSMutableArray *aRow; NSDebugLog(@"NSMatrix display\n"); rcnt = [rows count]; if (rcnt != num_rows) NSLog(@"NSMatrix internal error: num_rows != actual rows\n"); for (row=0; row