This is Matrix.m in view mode; [Download] [Up]
/* Implementation of Matrix class * * Copyright (C) 1993, 1994, 1995 The Board of Trustees of * The Leland Stanford Junior University. All Rights Reserved. * * Authors: Scott Francis, Mike Gravina, Fred Harris, Paul Kunz, Tom Pavel, * Imran Qureshi, and Libing Wang * Mike L. Kienenberger (Alaska) * * This file is part of an Objective-C class library for a window system * * Matrix.m,v 1.101 1995/12/13 22:33:04 fedor Exp */ /* Implementation notes: * * When reducing the size of the matrix, NeXTSTEP doesn't necessarily * free the unused cells. This "feature" has not been implemented here * */ #include "Matrix.h" /* Required for implementation: */ #include "ButtonCell.h" #include <objc/List.h> #include <objc/objc-api.h> #include "stdmacros.h" #include <stdlib.h> #include <objc/typedstream2.h> @interface View(WidgetSet) - _init; - _setAdjustedFrame:(const NXRect *)aFrame; - _sizeTo:(NXCoord)width :(NXCoord)height; @end @implementation Matrix /* Handy macro: */ #define CELL_INDEX(r,c) (r)*numCols+(c) /* Public methods */ // + initialize; + setCellClass:factoryId { return [self notImplemented:_cmd]; } - initFrame:(const NXRect *)frameRect { [super initFrame:frameRect]; cellSize.width = 100; cellSize.height = 17; intercell.width = 0; intercell.height = 0; if (!cellList) cellList = [[List alloc] init]; [self setCellClass:[ActionCell class]]; selectedCell = nil; selectedRow = -1; selectedCol = -1; return self; } - initFrame:(const NXRect *)frameRect mode:(int)aMode prototype:aCell numRows:(int)rowsHigh numCols:(int)colsWide { [self initFrame:frameRect]; [self setMode:aMode]; [self setPrototype:aCell]; [self renewRows:rowsHigh cols:colsWide]; return self; } - initFrame:(const NXRect *)frameRect mode:(int)aMode cellClass:factoryId numRows:(int)rowsHigh numCols:(int)colsWide { [self initFrame:frameRect]; [self setMode:aMode]; [self setCellClass:factoryId]; [self renewRows:rowsHigh cols:colsWide]; return self; } - free { [cellList freeObjects]; cellList = [cellList free]; if ( protoCell ) { [protoCell free]; } return [super free]; } - setCellClass:factoryId { cellClass = factoryId; return self; } - prototype { return protoCell; } - setPrototype:aCell { protoCell = aCell; /* give it new controlView */ [protoCell _setFrame:(NXRect *)0 inView:self]; return self; } - makeCellAt:(int)row :(int)col { ActionCell *newCell; NXRect cellFrame; if ( protoCell ) { newCell = [protoCell copy]; } else { newCell = [[cellClass alloc] init]; if ([newCell isKindOf:[ButtonCell class]]) { [(ButtonCell *)newCell _setMode:radioBehavior]; } } [self getCellFrame:&cellFrame at:row :col]; [newCell _setFrame:&cellFrame inView:self]; if ( widgetid ) { [newCell _managedBy:self]; } return newCell; } - (int)mode { [self notImplemented:_cmd]; return 0; } - setMode:(int)aMode { switch(aMode) { case NX_RADIOMODE: radioBehavior = YES; break; case NX_LISTMODE: radioBehavior = NO; break; default: break; } return self; } - setEmptySelectionEnabled:(BOOL)flag { allowEmptySel = flag; return self; } - (BOOL)isEmptySelectionEnabled { return allowEmptySel; } - sendAction:(SEL)aSelector to:anObject forAllCells:(BOOL)flag { id *members = NX_ADDRESS(cellList); id *last = members + [cellList count]; BOOL cont = YES; while (cont && members < last) { cont = [anObject perform:aSelector with:*members] ? YES : NO; members++; } return self; } - cellList { return cellList; } - selectedCell { return selectedCell; } - getSelectedCells:(List *)aList /* Implementation of selectedCell is very weak right now since Matrix * only allows one cell to be selected at any time */ { List *selList; if ( aList ) { selList = aList; } else { selList = [[List alloc] init]; } /* currently, only one cell can be selected */ if (selectedCell != nil) [selList addObject:selectedCell]; return selList; } - (int)selectedRow { return selectedRow; } - (int)selectedCol { return selectedCol; } - setSelectionByRect:(BOOL)flag { return [self notImplemented:_cmd]; } - (BOOL)isSelectionByRect { [self notImplemented:_cmd]; return 0; } - setSelectionFrom:(int)startPos to:(int)endPos anchor:(int)anchorPos lit:(BOOL)lit { return [self notImplemented:_cmd]; } - clearSelectedCell { Cell *temp = selectedCell; [selectedCell setState:0]; selectedCell = nil; return temp; } - selectCellAt:(int)row :(int)col { if (row < 0 || col < 0) { return [self clearSelectedCell]; } selectedRow = row; selectedCol = col; selectedCell = [self cellAt:row :col]; [selectedCell setState:1]; return selectedCell; } - selectAll:sender { int on = 1; [cellList makeObjectsPerform:@selector(setState) with:(id)&on]; return self; } - selectCell:aCell { Cell *tempCell; int i; selectedCell = [self getRow:&selectedRow andCol:&selectedCol ofCell:aCell]; /* Radio buttons:- set all off except the one selected */ if (selectedCell) { if (radioBehavior) { /* Radio */ i = [cellList count]; while ( i-- ) { tempCell = [cellList objectAt:i]; [tempCell setState:0]; } [selectedCell setState:1]; } } return selectedCell; } - selectCellWithTag:(int)anInt { Cell *aCell; int i; i = [cellList count]; while ( i-- ) { aCell = [cellList objectAt:i]; if ( [cell tag] == anInt ) { [self selectCell:aCell]; return self; } } return nil; } - getCellSize:(NXSize *)theSize { theSize->width = cellSize.width; theSize->height = cellSize.height; return self; } - setCellBackgroundGray:(float)value { /* FIXME! */ return self; } - setCellSize:(const NXSize *)aSize { cellSize.width = aSize->width; cellSize.height = aSize->height; return self; } - getIntercell:(NXSize *)theSize { theSize->width = intercell.width; theSize->height = intercell.height; return self; } - setIntercell:(const NXSize *)aSize { intercell.width = aSize->width; intercell.height = aSize->height; return self; } - setEnabled:(BOOL)flag { int i, count; count = [cellList count]; for (i=0; i < count; i++) { [[cellList objectAt:i] setEnabled:flag]; } return self; } - setScrollable:(BOOL)flag { return [self notImplemented:_cmd]; } - font { return font; } - setFont:fontObj { font = fontObj; return self; } - (float)backgroundGray { /* * only used in HippoDraw to make text same color as background so to make * test disappear. We can work around not having this. */ return 0.0; } - setBackgroundGray:(float)value { return [self notImplemented:_cmd]; } - setBackgroundColor:(NXColor)color { return [self notImplemented:_cmd]; } - (NXColor)backgroundColor { NXColor color; [self notImplemented:_cmd]; return color; } - setBackgroundTransparent:(BOOL)flag { return [self notImplemented:_cmd]; } - (BOOL)isBackgroundTransparent { [self notImplemented:_cmd]; return 0; } - setCellBackgroundColor:(NXColor)color { return [self notImplemented:_cmd]; } - (NXColor)cellBackgroundColor { NXColor color; [self notImplemented:_cmd]; return color; } - setCellBackgroundTransparent:(BOOL)flag { return [self notImplemented:_cmd]; } - (BOOL)isCellBackgroundTransparent { [self notImplemented:_cmd]; return 0; } - (float)cellBackgroundGray { [self notImplemented:_cmd]; return 0; } - setState:(int)value at:(int)row :(int)col { return [[self cellAt:row :col] setIntValue:value]; } - setIcon:(const char *)name at:(int)row :(int)col { return [[self cellAt:row :col] setIcon:name]; } - setTitle:(const char *)aString at:(int)row :(int)col { return [self notImplemented:_cmd]; } - (int)cellCount { return [cellList count]; } - getNumRows:(int *)rowCount numCols:(int *)colCount { *rowCount = numRows; *colCount = numCols; return self; } - cellAt:(int)row :(int)col { return [cellList objectAt:CELL_INDEX(row,col)]; } - getCellFrame:(NXRect *)theRect at:(int)row :(int)col { theRect->origin.x = col * (cellSize.width + intercell.width); theRect->origin.y = row * (cellSize.height + intercell.height); theRect->origin.y = frame.size.height - theRect->origin.y - cellSize.height; theRect->size.width = cellSize.width; theRect->size.height = cellSize.height; return self; } - getRow:(int *)row andCol:(int *)col ofCell:aCell { int index = [cellList indexOf:aCell]; if (index < 0) { return nil; } else { *col = index % numCols; *row = index / numCols; return aCell; } } - getRow:(int *)row andCol:(int *)col forPoint:(const NXPoint *)aPoint { return [self notImplemented:_cmd]; } - renewRows:(int)newRows cols:(int)newCols { /* Note: NeXTSTEP does not free unused cells when new size is smaller. */ int diff; diff = newRows - numRows; if (diff < 0) { selectedCell = NULL; selectedRow = -1; selectedCol = -1; } while (diff > 0) { [self addRow]; diff--; } while (diff < 0) { [self removeRowAt:(numRows-1) andFree:YES]; diff++; } diff = newCols - numCols; if (diff < 0) { selectedCell = NULL; selectedRow = -1; selectedCol = -1; } while (diff > 0) { [self addCol]; diff--; } while (diff < 0) { [self removeColAt:(numCols-1) andFree:YES]; diff++; } [cellList makeObjectsPerform:@selector(setState:) with:(id)&diff]; return self; } - putCell:newCell at:(int)row :(int)col { Cell *old = [cellList replaceObjectAt:CELL_INDEX(row,col) with:newCell]; return old; } - addRow { [self insertRowAt:numRows]; return self; } - insertRowAt:(int)row { Cell *aCell; int i; numRows++; if ( numCols <= 0 ) { return self; } for (i=0; i < numCols; i++) { aCell = [self makeCellAt:row :i]; [cellList insertObject:aCell at:CELL_INDEX(row,i)]; } return self; } - addCol { [self insertColAt:numCols]; return self; } - insertColAt:(int)col { Cell *aCell; int i; numCols++; if ( numRows <= 0 ) { return self; } for (i=0; i < numRows; i++) { aCell = [self makeCellAt:i :col]; [cellList insertObject:aCell at:CELL_INDEX(i,col)]; } return self; } - removeColAt:(int)col andFree:(BOOL)flag { Cell *aCell; int i; i = numRows; while( i-- ) { aCell = [cellList removeObjectAt:CELL_INDEX(i,col)]; if (flag) [aCell free]; } numCols--; return self; } - removeRowAt:(int)row andFree:(BOOL)flag { Cell *aCell; int i; i = numCols; while ( i-- ) { aCell = [cellList removeObjectAt:CELL_INDEX(row, i)]; if (flag) [aCell free]; } numRows--; return self; } - findCellWithTag:(int)anInt { Cell *aCell; int i; i = [cellList count]; while( i-- ) { aCell = [cellList objectAt:i]; if ( [aCell tag] == anInt ) return aCell; } return nil; } - setTag:(int)anInt at:(int)row :(int)col { return [[self cellAt:row :col] setTag:anInt]; } - target { return target; } - setTarget:anObject { target = anObject; return self; } - setTarget:anObject at:(int)row :(int)col { [[self cellAt:row :col] setTarget:anObject]; return self; } - (SEL)action { return action; } - setAction:(SEL)aSelector { action = aSelector; return self; } - (SEL)doubleAction { return doubleAction; } - setDoubleAction:(SEL)aSelector { doubleAction = aSelector; return self; } - (SEL)errorAction { return errorAction; } - setErrorAction:(SEL)aSelector { errorAction = aSelector; return self; } - setAction:(SEL)aSelector at:(int)row :(int)col { [[self cellAt:row :col] setAction:aSelector]; return self; } - setTag:(int)anInt target:anObject action:(SEL)aSelector at:(int)row :(int)col { Cell *aCell; aCell = [self cellAt:row :col]; [aCell setTag:anInt]; [aCell setTarget:anObject]; [aCell setAction:aSelector]; return self; } - setAutosizeCells:(BOOL)flag { return [self notImplemented:_cmd]; } - (BOOL)doesAutosizeCells { [self notImplemented:_cmd]; return 0; } - sizeTo:(float)width :(float)height { return [self notImplemented:_cmd]; } - sizeToCells { if (numCols) frame.size.width = numCols*cellSize.width+ (numCols-1)*intercell.width; else frame.size.width = 0; if (numRows) frame.size.height = numRows*cellSize.height+ (numRows-1)*intercell.height; else frame.size.height = 0; return self; } - sizeToFit { int i; NXSize theSize,maxSize={0.0,0.0}; i = [cellList count]; while ( i-- ) { [[cellList objectAt:i] calcCellSize:&theSize]; maxSize.width = MAX(maxSize.width, theSize.width); maxSize.height= MAX(maxSize.height,theSize.height); } cellSize = maxSize; return [self sizeToCells]; } - validateSize:(BOOL)flag { return [self notImplemented:_cmd]; } - calcSize { return [self notImplemented:_cmd]; } - drawCell:aCell { return [self notImplemented:_cmd]; } - drawCellInside:aCell { return [self notImplemented:_cmd]; } - drawCellAt:(int)row :(int)col { return [self notImplemented:_cmd]; } - highlightCellAt:(int)row :(int)col lit:(BOOL)flag { return [self notImplemented:_cmd]; } - drawSelf:(const NXRect *)rects :(int)rectCount { return self; } - display { return self; } - setAutoscroll:(BOOL)flag { return [self notImplemented:_cmd]; } - scrollCellToVisible:(int)row :(int)col { /* This is highly desireable frill for phase 2 */ return self; } - setReaction:(BOOL)flag { return [self notImplemented:_cmd]; } - (int)mouseDownFlags { [self notImplemented:_cmd]; return 0; } - mouseDown:(NXEvent *)theEvent { return [self notImplemented:_cmd]; } - (BOOL)performKeyEquivalent:(NXEvent *)theEvent { [self notImplemented:_cmd]; return 0; } - sendAction:(SEL)theAction to:theTarget { SEL a = theAction; id t = theTarget; if (!a) { a = action; } if ( !t ) { t = target; } return [super sendAction:a to:t]; } - sendAction { if ( selectedCell && [selectedCell action] ) { if ( [selectedCell target] ) { [[selectedCell target] perform:[selectedCell action] with:self]; } else { [target perform:[selectedCell action] with:self]; } } else { [target perform:action with:self]; } return self; } - sendDoubleAction { return [self notImplemented:_cmd]; } - textDelegate { return textDelegate; } - setTextDelegate:anObject { textDelegate = anObject; return self; } - (BOOL)textWillEnd:textObject { [self notImplemented:_cmd]; return 0; } - (BOOL)textWillChange:textObject { [self notImplemented:_cmd]; return 0; } - textDidEnd:textObject endChar:(unsigned short)whyEnd { return [self notImplemented:_cmd]; } - textDidChange:textObject { return [self notImplemented:_cmd]; } - textDidGetKeys:textObject isEmpty:(BOOL)flag { return [self notImplemented:_cmd]; } - selectText:sender { return [self notImplemented:_cmd]; } - selectTextAt:(int)row :(int)col { return [self notImplemented:_cmd]; } - setPreviousText:anObject { return [self notImplemented:_cmd]; } - setNextText:anObject { return [self notImplemented:_cmd]; } - (BOOL)acceptsFirstMouse { [self notImplemented:_cmd]; return 0; } - write:(NXTypedStream *)stream { return self; } - read:(TypedStream*)stream { Cell *aCell; char *cellClassName; int i, h, w; [super read:stream]; /* A matrix with one row will have its cell ivar set to the * cell that is in the cellList. We must set it to nil * so that Control super class wouldn't attempt to use it. */ if ( cell ) { cell = nil; } objc_read_object(stream,&cellList); objc_read_type(stream,"*",&cellClassName); cellClass = objc_get_class(cellClassName); objc_read_object(stream, &protoCell); objc_read_types(stream, "ii", &w, &h); cellSize.width = w; cellSize.height = h; objc_read_types(stream,"ii",&numRows,&numCols); objc_read_types(stream, "ii", &selectedRow, &selectedCol); objc_read_type(stream,"i",&radioBehavior); i = [cellList count]; while ( i-- ) { aCell = [cellList objectAt:i]; if ([aCell isKindOf:[ButtonCell class]]) { [(ButtonCell *)aCell _setMode:radioBehavior]; } } return self; } - awake { int i; [super awake]; instancename = "Matrix"; /* replace these later */ intercell.width = 0; intercell.height = 0; if (!cellList) cellList = [[List alloc] init]; /* maybe the following should be moved to awakeFromNib? */ i = [cellList count]; while ( i-- ) { id newCell = [cellList objectAt:i]; [newCell _setControlView:self]; if ( widgetid ) [newCell _managedBy:self]; } if ((-1 != selectedRow) && (-1 != selectedCol)) selectedCell = [self cellAt:selectedRow :selectedCol]; else selectedCell = nil; return self; } - resetCursorRects { return [self notImplemented:_cmd]; } // + newFrame:(const NXRect *)frameRect; // + newFrame:(const NXRect *)frameRect mode:(int)aMode prototype:aCell // numRows:(int)rowsHigh numCols:(int)colsWide; // + newFrame:(const NXRect *)frameRect mode:(int)aMode cellClass:factoryId // numRows:(int)rowsHigh numCols:(int)colsWide; - (int)getMode { return radioBehavior; } - _init { [super _init]; instancename = "Matrix"; return self; } - _calcInterCellSize { intercell.width = frame.size.width - (numCols) * cellSize.width; intercell.height = frame.size.height - (numRows) * cellSize.height; if ( numCols > 1 ) { intercell.width /= (numCols - 1); } else { intercell.width = 0; } if ( numRows > 1 ) { intercell.height /= (numRows -1); } else { intercell.height = 0; } return self; } - _managedBy:parent wid:(void*)widget { int i, count; int row, col; NXRect cellRect; id myCell; [super _managedBy:parent wid:widget]; [self _calcInterCellSize]; count = [cellList count]; for (i = 0; i < count; i++) { myCell = [cellList objectAt:i]; [self getRow:&row andCol:&col ofCell:myCell]; [self getCellFrame:&cellRect at:row :col]; [myCell _setFrame:&cellRect inView:self]; [myCell _managedBy:self]; } return self; } - _destroy { Cell *aCell; int i; [super _destroy]; i = [cellList count]; while ( i-- ) { aCell = [cellList objectAt:i]; [aCell _destroy]; } return self; } - _setAdjustedFrame:(const NXRect *)aFrame { /* This method adjusts the position and size of the matrix's * frame to accomodate widgets that need a larger frame * due to the selection border. It uses it's super view * (Control) by temporarily setting a cell. */ cell = [cellList objectAt:0]; [super _setAdjustedFrame:aFrame]; cell = nil; return self; } - _sizeTo:(NXCoord)width :(NXCoord)height { /* Temporarily set a cell, so super (Control) can do the work */ cell = [cellList objectAt:0]; [super _sizeTo: width :height]; cell = nil; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.