
/* Generated by Interface Builder */

#import "ColumnMatrix.h"

@implementation ColumnMatrix

+ newFrame:(const NXRect *)frameRect
{
  id		newPrototype;
  NXSize	newIntercell = {0.0, 0.0},
  		newCellSize;
  char		**data = calloc(1, sizeof(char *));
  float		*tab = calloc(1, sizeof(float));

  self = [super newFrame:frameRect
			      mode:NX_LISTMODE
			      prototype:[IconColumnCell new]
			      numRows:0 numCols:1];
  [protoCell setBordered:TRUE];
  [protoCell setAlignment:NX_LEFTALIGNED];

  // this whole section is an ugly kluge because the protoCell
  // won't return the correct calcCellSize, since it has no
  // data.  if we give it data, the clones won't work.  so we
  // create a new prototype cell, and get its size.
  newPrototype = [IconColumnCell new];
  [newPrototype setBordered:TRUE];
  [newPrototype setNumColumns:1];
  [newPrototype setTabs:tab];
  data[0] = "data";
  [newPrototype setData:data];
  [newPrototype calcCellSize:&newCellSize];
  [newPrototype free];
  newCellSize.height--;
  newCellSize.width = frameRect->size.width;

  [self setCellSize:&newCellSize];
  [self setIntercell:&newIntercell];
  [self setBackgroundGray:NX_LTGRAY];
  [self setAutoscroll:TRUE];

  itemsList = [HashList new];

  return self;
}


- (BOOL)acceptsFirstResponder
{
  return TRUE;
}

- superviewSizeChanged:(const NXSize*)oldSize
{
  NXSize	newCellSize;
  
  [super superviewSizeChanged:oldSize];

  newCellSize.width = bounds.size.width;
  newCellSize.height = cellSize.height;
  [self setCellSize:&newCellSize];
  [self calcTabs];
  return self;
}

- calcTabs
{
  int		i, cellIndex;

  for (i=0; i<numColumns; i++) {
    realTabs[i] = tabs[i] * bounds.size.width;
  }
  
  [protoCell setTabs:(float *)&realTabs];
  for (cellIndex=0; cellIndex<numRows; cellIndex++)
    [((List *)cellList)->dataPtr[cellIndex] setTabs:(float *)&realTabs];

  return self;
}

#ifdef STUPID
- _mouseDown_listMode:(NXEvent *)event;
{
  int	cellIndex;
  Item	*item;
  id	ret;
  BOOL	kill = FALSE;

  firstCheckRow = numRows+1;
  lastCheckRow = 0;
  
  ret = [super _mouseDown_listMode:event];

  for (cellIndex = lastCheckRow; cellIndex >= firstCheckRow; cellIndex--) {
    item = (((IconColumnCell *)
    	(((List*)cellList)->dataPtr[cellIndex]))->aux);
#ifdef DEBUG
printf("Checking cell %d, visible %d\n", cellIndex, item->shown);
#endif
    if (!item->shown) {
      kill = TRUE;
      [self removeRowAt:cellIndex andFree:TRUE];
    }
  }
  if (kill) {
    [self updateCells];
    [[self superview] display];
  }

  return ret;
}
#endif

- _highlightCellAt:(int)row :(int)col lit:(BOOL)lit andDraw:(BOOL)draw
{
  Item	*item;
  
#ifdef STUPID
  if (!lit) {
    item = (((IconColumnCell *)(((List *)cellList)->dataPtr[row]))->aux);
    if (![self itemVisible:item]) {
      firstCheckRow = MIN(firstCheckRow, row);
      lastCheckRow = MAX(lastCheckRow, row);
    }
  }
#endif

  [super _highlightCellAt:row :col lit:lit andDraw:draw];
  return [self drawCellAt:row :col];
}


- updateCells
{
  int			itemIndex, cellIndex, newCellCount = 0,
  			itemCount = [itemsList count];
  int			prevItemIndex, row, col, nextRow;
  Item			*item, *prevItem;
  IconColumnCell	*aCell;
  BOOL			wasShown, add = FALSE, kill = FALSE;
  
  if (!numRows) {
    // boy, is this ugly, and boy, is it fast.
    for (itemIndex=0; itemIndex<itemCount; itemIndex++) {
      item = ((List *)itemsList)->dataPtr[itemIndex];
      
      newCellCount += [self itemVisible:item];
    }

    [self setCellCount:newCellCount];
    for (itemIndex=0, cellIndex=0; itemIndex<itemCount; itemIndex++) {
      item = ((List *)itemsList)->dataPtr[itemIndex];
      
      if (item->shown) {
	item->cell = ((List *)cellList)->dataPtr[cellIndex];
	[((List *)cellList)->dataPtr[cellIndex] setAux:item];
	cellIndex++;
      } else {
	item->cell = nil;
      }
    }
    [self sizeToCells];
    [self selectCellAt:-1 :-1];
    add = (newCellCount > 0);
      
 } else {
    
    for (itemIndex=0; itemIndex<itemCount; itemIndex++) {
      item = ((List *)itemsList)->dataPtr[itemIndex];
      wasShown = item->shown;
      
      newCellCount += [self itemVisible:item];
      if ((wasShown) && (!item->shown)) {
        kill = TRUE;
	((IconColumnCell *)(item->cell))->aux = nil;
	item->cell = nil;
      } else if ((!wasShown) && (item->shown)) {
        add = TRUE;
        item->cell = nil;
      }
    }
    
    if (kill) {
      for (cellIndex=numRows-1; cellIndex >= 0; cellIndex--) {
	aCell = [cellList objectAt:cellIndex];
	
	if (!aCell->aux)
	  [self removeRowAt:cellIndex andFree:TRUE];
      }
      
      for (itemIndex=0, cellIndex=0; itemIndex<itemCount; itemIndex++) {
	item = ((List *)itemsList)->dataPtr[itemIndex];
	
	if (item->cell && item->shown) {
	  if (cellIndex >= numRows)
	    exit(1);
	  
	  item->cell = ((List *)cellList)->dataPtr[cellIndex];
	  [((List *)cellList)->dataPtr[cellIndex] setAux:item];
	  cellIndex++;
	}
      }
    }
    
    if (add) {
      for (itemIndex=itemCount-1; itemIndex >= 0; itemIndex--) {
	item = ((List *)itemsList)->dataPtr[itemIndex];
	
	if (item->shown && !item->cell) {
	  nextRow = 0;
	  for (prevItemIndex=itemIndex-1; (nextRow == 0)&&(prevItemIndex >= 0);
	  		 prevItemIndex--) {
	    if ((prevItem=((List *)itemsList)->dataPtr[prevItemIndex])->cell) {
	      if ([self getRow:&row andCol:&col ofCell:prevItem->cell]) {
                nextRow = row+1;
	      }
	    }
	  }
	  [self insertRowAt:nextRow];
	  item->cell = ((List *)cellList)->dataPtr[nextRow];
	  [((List *)cellList)->dataPtr[nextRow] setAux:item];
	}
      }
      
      for (itemIndex=0, cellIndex=0; itemIndex<itemCount; itemIndex++) {
	item = ((List *)itemsList)->dataPtr[itemIndex];
	
	if (item->shown) {
	  item->cell = ((List *)cellList)->dataPtr[cellIndex];
	  [((List *)cellList)->dataPtr[cellIndex] setAux:item];
	  cellIndex++;
	}
      }
    }
    
    [self sizeToCells];
  }

  if (add || kill)
    return nil;
  else
    return self;
}

- setCell:aCell fromItem:item
{
  [item setCell:aCell];
  [aCell setAux:item];
  return self;
}

// Hmm, this is just begging to be subclassed, eh?
- (BOOL)itemVisible:item
{
  return TRUE;
}

- setCellCount:(int)newCount
{
  int	i;
  
//  if (newCount > numRows)
    [self renewRows:newCount cols:1];
//  else
//    while (newCount < numRows)
//      [self removeRowAt:numRows-1 andFree:TRUE];

  return self;
}

- empty
{
  [itemsList freeObjects];
  [self setCellCount:0];
  [self sizeToCells];
  [[self superview] display];
  [self selectCellAt:-1 :-1];
  [self sendAction];
  return self;
}


- selectedCell
{
  return realSelectedCell;
}

- selectAll:sender
{
  int	cellIndex;
  
  for (cellIndex = 0; cellIndex < [cellList count]; cellIndex++) {
//    [[cellList objectAt:cellIndex] setIntValue:TRUE];
    [self highlightCellAt:cellIndex :0 lit:TRUE];
  }
  selectedRow = [cellList count];
  selectedCell = [cellList objectAt:selectedRow];
  [self sendAction];
  
  return [[self superview] display];
}


- sendAction:(SEL)theAction to:theTarget
{
  int	cellIndex;
  id	ret;
  
  if (refreshTarget) {
    refreshTarget = FALSE;
    realSelectedCell = nil;
    [super sendAction:theAction to:theTarget];
  }
    
  firstSelectedRow = -1;
  lastSelectedRow = numRows;

  for (cellIndex=0; cellIndex<numRows; cellIndex++) {
    if ([(id)(((List *)cellList)->dataPtr[cellIndex]) isHighlighted]) {
      lastSelectedRow = cellIndex;
      if (firstSelectedRow == -1)
        firstSelectedRow = cellIndex;
    }
  }

  if ((firstSelectedRow == lastSelectedRow) && (firstSelectedRow >= 0)) {
    realSelectedRow = firstSelectedRow;
    realSelectedCell = ((List *)cellList)->dataPtr[realSelectedRow];
    [self scrollCellToVisible:realSelectedRow :0];
  } else {
    realSelectedRow = lastSelectedRow = firstSelectedRow = -1;
    realSelectedCell = nil;
  }

  ret = [super sendAction:theAction to:theTarget];

  if (![self updateCells]) {
    [[self superview] display];
    [self sendAction];
  }
  
  return ret;
}

- selectUp:sender
{
  if ((firstSelectedRow > 0) && (firstSelectedRow <= numRows-1)) {
    [self selectCellAt:--firstSelectedRow :0];
    [self sendAction];
  } else if (firstSelectedRow == 0) {
    [self selectWayUp:sender];
  } else {
    [self selectCellAt:numRows-1 :0];
    [self sendAction];
  }
  return self;
}

- selectDown:sender
{
  if ((lastSelectedRow >= 0) && (lastSelectedRow < numRows-1)) {
    [self selectCellAt:++lastSelectedRow :0];
    [self sendAction];
  } else if (lastSelectedRow == numRows-1) {
    [self selectWayDown:sender];
  } else {
    [self selectCellAt:0 :0];
    [self sendAction];
  }
  return self;
}

// Subclass, perchance to use.
- selectWayUp:sender
{
  return self;
}
- selectWayDown:sender
{
  return self;
}

@end
