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.