home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-03-31 | 32.8 KB | 1,048 lines |
- //=============================================================================
- //
- // Copyright (C) 1995,1996,1997,1998 by Paul S. McCarthy and Eric Sunshine.
- // Written by Paul S. McCarthy and Eric Sunshine.
- // All Rights Reserved.
- //
- // This notice may not be removed from this source code.
- //
- // This object is included in the MiscKit by permission from the authors
- // 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.
- //
- //=============================================================================
- //-----------------------------------------------------------------------------
- // MiscTableView.M
- //
- // General-purpose 2-D display object that works with the
- // MiscTableScroll to provide row/column sizing and dragging.
- //
- // This object is responsible for drawing, mouse and keyboard
- // events in the content portion of the display.
- //
- //-----------------------------------------------------------------------------
- //-----------------------------------------------------------------------------
- // $Id: MiscTableView.M,v 1.38 98/03/29 23:58:32 sunshine Exp $
- // $Log: MiscTableView.M,v $
- // Revision 1.38 98/03/29 23:58:32 sunshine
- // v138.1: Now uses NSColor's "system" color for grid rather than "gray".
- //
- // Revision 1.37 98/03/22 13:13:33 sunshine
- // v133.1: Added support to draw clipped text.
- //
- // Revision 1.36 97/11/23 07:41:07 sunshine
- // v130.1: Broke off MiscTableViewDrag.M and MiscTableViewCursor.M
- //-----------------------------------------------------------------------------
- #import "MiscTableViewPrivate.h"
- #import "MiscColorList.h"
- #import "MiscDrawList.h"
- #import "MiscGeometry.h"
- #import "MiscHighlightTracker.h"
- #import "MiscListTracker.h"
- #import "MiscRadioTracker.h"
- #import "MiscRectColorList.h"
- #import "MiscRectList.h"
- #import "MiscSparseSet.h"
- #import "MiscTableBorder.h"
- #import "MiscTableScrollPrivate.h"
- #import <MiscTableScroll/MiscTableCell.h>
- #import <MiscTableScroll/MiscTableScroll.h>
- #import <new.h>
-
- extern "Objective-C" {
- #import <AppKit/NSApplication.h>
- #import <AppKit/NSControl.h> // Control-text notifications
- #import <AppKit/NSText.h>
- #import <AppKit/psops.h>
- }
-
- extern "C" {
- #import <math.h> // floor()
- }
-
- //-----------------------------------------------------------------------------
- // dump_map
- //-----------------------------------------------------------------------------
- // static void dump_map( NSString* label, int const* map, int nc, int nr )
- // {
- // fprintf( stderr, "%s nc=%d, nr=%d\n", [label lossyCString], nc, nr );
- // int const* p = map;
- // for (int r = 0; r < nr; r++)
- // {
- // for (int c = 0; c < nc; c++, p++)
- // fprintf( stderr, " %d", *p );
- // fprintf( stderr, "\n" );
- // }
- // }
-
-
- //-----------------------------------------------------------------------------
- // extract_rect
- // Extract a contiguous rectangular group of cells to be drawn from
- // this boolean map of cells that need drawing.
- //
- // 1) Find the first cell that needs to be drawn (c0,r0).
- // 2) Include all contiguous following cells on the same row
- // that also need to be drawn (cN,r0).
- // 3) Include all contiguous following rows in which (c0..cN)
- // all need to be drawn.
- // 4) Clear the flags from the map to indicate that these cells
- // do not need to be drawn again.
- //-----------------------------------------------------------------------------
- static int extract_rect( int* map, int nc, int nr,
- MiscCoord_V& c0, MiscCoord_V& r0,
- MiscCoord_V& cN, MiscCoord_V& rN )
- {
- int* p = map;
- int* plim = p + (nc * nr);
-
- while (p < plim && *p == 0)
- p++;
-
- if (p >= plim)
- return 0; // *** RETURN ***
-
- int rc = *p;
-
- int r, c;
-
- int const n = p - map;
- r0 = n / nc;
- c0 = n % nc;
-
- c = c0;
- while (c < nc && *p == rc)
- {
- c++;
- p++;
- }
- cN = c - 1;
-
- int const num_cols = (c - c0);
-
- r = r0;
- do {
- p -= num_cols;
- memset( p, 0, num_cols * sizeof(*p) );
- if (++r >= nr)
- break;
- p += nc;
- plim = p + num_cols;
- while (p < plim && *p == rc)
- p++;
- }
- while (p >= plim);
-
- rN = r - 1;
-
- return rc;
- }
-
-
- //=============================================================================
- // IMPLEMENTATION
- //=============================================================================
- @implementation MiscTableView
-
- //-----------------------------------------------------------------------------
- // scroll
- //-----------------------------------------------------------------------------
- - (id)scroll
- {
- return [self enclosingScrollView];
- }
-
-
- //-----------------------------------------------------------------------------
- // - initWithFrame:scroll:colInfo:rowInfo:
- //
- // NOTE *1*: Default behavior is to take keyboard-cursor information from
- // the row-border.
- //-----------------------------------------------------------------------------
- - (id)initWithFrame:(NSRect)rect
- scroll:(MiscTableScroll*)scroll
- colInfo:(MiscTableBorder*)i_col_border
- rowInfo:(MiscTableBorder*)i_row_border
- {
- NSZone* const z = [self zone];
-
- rect.size.width = i_col_border->totalSize();
- rect.size.height = i_row_border->totalSize();
-
- [super initWithFrame:rect];
-
- colBorder = i_col_border;
- rowBorder = i_row_border;
- trackerBorder = MISC_ROW_BORDER; // NOTE *1*
-
- oldColSel = new( NSZoneMalloc(z,sizeof(*oldColSel)) ) MiscSparseSet;
- oldRowSel = new( NSZoneMalloc(z,sizeof(*oldRowSel)) ) MiscSparseSet;
- [self setSelectionMode:[scroll selectionMode]];
-
- inhibitCursor = 0;
- cursorSlot = -1;
- return self;
- }
-
-
- //-----------------------------------------------------------------------------
- // - dealloc
- //-----------------------------------------------------------------------------
- - (void)dealloc
- {
- [[self scroll] abortEditing];
- [tracker release];
- NSZone* const z = [self zone];
- if (oldColSel != 0)
- {
- oldColSel->MiscSparseSet::~MiscSparseSet();
- NSZoneFree( z, oldColSel );
- }
- if (oldRowSel != 0)
- {
- oldRowSel->MiscSparseSet::~MiscSparseSet();
- NSZoneFree( z, oldRowSel );
- }
- [super dealloc];
- }
-
-
- //-----------------------------------------------------------------------------
- // - isFlipped
- //-----------------------------------------------------------------------------
- - (BOOL)isFlipped
- {
- return YES;
- }
-
-
- //-----------------------------------------------------------------------------
- // - isOpaque
- //-----------------------------------------------------------------------------
- - (BOOL)isOpaque
- {
- return YES;
- }
-
-
- //-----------------------------------------------------------------------------
- // - acceptsFirstMouse:
- //-----------------------------------------------------------------------------
- - (BOOL)acceptsFirstMouse:(NSEvent*)theEvent
- {
- return YES;
- }
-
-
- //-----------------------------------------------------------------------------
- // - acceptsFirstResponder
- //-----------------------------------------------------------------------------
- - (BOOL)acceptsFirstResponder
- {
- return YES;
- }
-
-
- //-----------------------------------------------------------------------------
- // - adjustSize
- //-----------------------------------------------------------------------------
- - (void)adjustSize
- {
- [self setFrameSize:
- NSMakeSize( colBorder->totalSize(), rowBorder->totalSize() )];
- }
-
-
- //=============================================================================
- // TYPE VARIATIONS
- //=============================================================================
-
- - (MiscTableBorder*)borderFor:(MiscBorderType)b
- { return (b == MISC_ROW_BORDER ? rowBorder : colBorder); }
- - (MiscTableBorder*)otherBorder:(MiscBorderType)b
- { return [self borderFor:MISC_OTHER_BORDER(b)]; }
-
-
- //=============================================================================
- // FRAMES
- //=============================================================================
- //-----------------------------------------------------------------------------
- // - cellFrameAtRow:column: -- Physical coords
- //-----------------------------------------------------------------------------
- - (NSRect)cellFrameAtRow:(MiscCoord_P)row column:(MiscCoord_P)col
- {
- if (row < 0 || row >= rowBorder->count() ||
- col < 0 || col >= colBorder->count())
- return NSMakeRect( 0, 0, 0, 0 );
- else
- {
- MiscCoord_V v_row = rowBorder->physicalToVisual( row );
- MiscCoord_V v_col = colBorder->physicalToVisual( col );
- return NSMakeRect( colBorder->getOffset(v_col),
- rowBorder->getOffset(v_row),
- colBorder->effectiveSize(v_col),
- rowBorder->effectiveSize(v_row) );
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // - cellInsideAtRow:column: -- Actual cell frame inside border lines
- //-----------------------------------------------------------------------------
- - (NSRect)cellInsideAtRow:(MiscCoord_P)row column:(MiscCoord_P)col
- {
- NSRect r = [self cellFrameAtRow:row column:col];
- if (!NSIsEmptyRect(r))
- {
- r.size.width--;
- r.size.height--;
- }
- return r;
- }
-
-
- //-----------------------------------------------------------------------------
- // - getSlotFrameAt:from: -- Physical coords
- //-----------------------------------------------------------------------------
- - (NSRect)getSlotFrameAt:(MiscCoord_P)pslot from:(MiscBorderType)bdr
- {
- MiscTableBorder* const b = [self borderFor:bdr];
- if (pslot < 0 || pslot >= b->count())
- return NSZeroRect;
- else
- {
- MiscCoord_V vslot = b->physicalToVisual( pslot );
- MiscRect_O ro( bdr, [self bounds] );
- ro.setX_O( b->getOffset(vslot) );
- ro.setWidth_O( b->effectiveSize(vslot) );
- return (NSRect)ro;
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // - getSlotInsideAt:from: -- Physical coords
- //-----------------------------------------------------------------------------
- - (NSRect)getSlotInsideAt:(MiscCoord_P)slot from:(MiscBorderType)bdr
- {
- NSRect r = [self getSlotFrameAt:slot from:bdr];
- if (!NSIsEmptyRect(r))
- {
- r.size.width--;
- r.size.height--;
- }
- return r;
- }
-
-
- //-----------------------------------------------------------------------------
- // - getRow:column:forPoint:
- //-----------------------------------------------------------------------------
- - (BOOL)getRow:(int*)row column:(int*)col forPoint:(NSPoint)pt
- {
- if (NSPointInRect( pt, [self bounds] ))
- {
- MiscCoord_V const vr = rowBorder->visualForOffset( (MiscPixels)pt.y );
- MiscCoord_V const vc = colBorder->visualForOffset( (MiscPixels)pt.x );
- *row = rowBorder->visualToPhysical( vr );
- *col = colBorder->visualToPhysical( vc );
- return YES;
- }
- return NO;
- }
-
-
- //=============================================================================
- // VISIBLE / SCROLLING STUFF
- //=============================================================================
- //-----------------------------------------------------------------------------
- // - firstVisibleSlot: -- Physical coord
- //-----------------------------------------------------------------------------
- - (int)firstVisibleSlot:(MiscBorderType)bdr
- {
- MiscCoord_P ret = -1;
- MiscTableBorder* const b = [self borderFor:bdr];
- int const lim = b->count();
- if (lim > 0)
- {
- MiscRect_O r( bdr, [self visibleRect] );
- MiscPixels const vorg = r.getX_O();
- MiscPixels const vlim = r.getMaxX_O();
- MiscCoord_V v = b->visualForOffset( vorg );
- if (v < lim - 1 && b->getOffset(v) < vorg && b->getOffset(v+1) < vlim)
- v++; // First slot whose leading edge is visible
- ret = b->visualToPhysical( v );
- }
- return ret;
- }
-
-
- //-----------------------------------------------------------------------------
- // - lastVisibleSlot: -- Physical coord
- //-----------------------------------------------------------------------------
- - (int)lastVisibleSlot:(MiscBorderType)bdr
- {
- MiscCoord_P ret = -1;
- MiscTableBorder* const b = [self borderFor:bdr];
- if (b->count() > 0)
- {
- MiscRect_O r( bdr, [self visibleRect] );
- MiscPixels const vorg = r.getX_O();
- MiscPixels const vlim = r.getMaxX_O();
- MiscCoord_V v = b->visualForOffset( vlim );
- if (v > 0 && b->getOffset(v) + b->effectiveSize(v) > vlim &&
- b->getOffset(v-1) + b->effectiveSize(v-1) > vorg)
- v--; // Last slot whose trailing edge is visible
- ret = b->visualToPhysical( v );
- }
- return ret;
- }
-
-
- //-----------------------------------------------------------------------------
- // - numberOfVisibleSlots:
- //-----------------------------------------------------------------------------
- - (int)numberOfVisibleSlots:(MiscBorderType)bdr
- {
- MiscTableBorder* const b = [self borderFor:bdr];
- if (b->count() > 0)
- {
- MiscRect_O r( bdr, [self visibleRect] );
- MiscPixels const vorg = r.getX_O();
- MiscPixels const vlim = r.getMaxX_O();
- MiscCoord_V const first = b->visualForOffset( vorg );
- MiscCoord_V const last = b->visualForOffset( vlim );
- return last - first + 1;
- }
- return 0;
- }
-
-
- //-----------------------------------------------------------------------------
- // - border:slotIsVisible: -- Physical coord
- //-----------------------------------------------------------------------------
- - (BOOL)border:(MiscBorderType)bdr slotIsVisible:(int)n
- {
- MiscTableBorder* const b = [self borderFor:bdr];
- if (b->count() > 0)
- {
- MiscCoord_V const x = b->physicalToVisual(n);
- MiscPixels const xorg = b->getOffset(x);
- MiscPixels const xlim = xorg + b->effectiveSize(x);
- MiscRect_O r( bdr, [self visibleRect] );
- MiscPixels const vorg = r.getX_O();
- MiscPixels const vlim = r.getMaxX_O();
- return xorg <= vlim && xlim >= vorg;
- }
- return NO;
- }
-
-
- //-----------------------------------------------------------------------------
- // - border:setFirstVisibleSlot: -- Physical coord
- //-----------------------------------------------------------------------------
- - (void)border:(MiscBorderType)bdr setFirstVisibleSlot:(int)n
- {
- MiscTableBorder* const b = [self borderFor:bdr];
- int const num_slots = b->count();
- if (0 <= n && n < num_slots)
- {
- MiscCoord_V const x = b->physicalToVisual(n);
- MiscPixels const xorg = b->getOffset(x);
- MiscRect_O r( bdr, [[self superview] bounds] );
- r.setX_O( xorg );
- [self scrollPoint:r];
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // - border:setLastVisibleSlot: -- Physical coord
- //-----------------------------------------------------------------------------
- - (void)border:(MiscBorderType)bdr setLastVisibleSlot:(int)n
- {
- MiscTableBorder* const b = [self borderFor:bdr];
- int const num_slots = b->count();
- if (0 <= n && n < num_slots)
- {
- MiscPixels const vwidth =
- MiscRect_O( bdr, [self visibleRect] ).getWidth_O();
- MiscCoord_V const x = b->physicalToVisual(n);
- MiscPixels const vorg = b->getOffset(x) + b->effectiveSize(x) - vwidth;
- MiscRect_O r( bdr, [[self superview] bounds] );
- r.setX_O( vorg );
- [self scrollPoint:r];
- }
- }
-
-
- //=============================================================================
- // SCROLLING
- //=============================================================================
- //-----------------------------------------------------------------------------
- // - scrollCellToVisibleAtRow:column: -- Physical coords
- //-----------------------------------------------------------------------------
- - (void)scrollCellToVisibleAtRow:(int)row column:(int)col
- {
- [self scrollRectToVisible:[self cellFrameAtRow:row column:col]];
- }
-
-
- //-----------------------------------------------------------------------------
- // - border:scrollToVisible: -- Physical coord
- //-----------------------------------------------------------------------------
- - (void)border:(MiscBorderType)bdr scrollToVisible:(MiscCoord_P)pslot
- {
- MiscTableBorder* const b = [self borderFor:bdr];
- MiscCoord_V const vslot = b->physicalToVisual( pslot );
- NSRect v = [self visibleRect];
- MiscRect_O r( bdr, v );
- r.setX_O( b->getOffset(vslot) );
- r.setWidth_O( b->effectiveSize(vslot) );
- [self scrollRectToVisible:r];
- }
-
-
- //-----------------------------------------------------------------------------
- // - scrollRowToVisible: -- Physical coord
- //-----------------------------------------------------------------------------
- - (void)scrollRowToVisible:(int)row
- {
- [self border:MISC_ROW_BORDER scrollToVisible:row];
- }
-
-
- //-----------------------------------------------------------------------------
- // - scrollColToVisible: -- Physical coord
- //-----------------------------------------------------------------------------
- - (void)scrollColumnToVisible:(int)col
- {
- [self border:MISC_COL_BORDER scrollToVisible:col];
- }
-
-
- //=============================================================================
- // DRAWING
- //=============================================================================
- //-----------------------------------------------------------------------------
- // - cMin:cMax:rMin:rMax:forRect:
- //-----------------------------------------------------------------------------
- - (void)cMin:(MiscCoord_V*)cmin cMax:(MiscCoord_V*)cmax
- rMin:(MiscCoord_V*)rmin rMax:(MiscCoord_V*)rmax
- forRect:(NSRect)nsrect
- {
- *cmin = colBorder->visualForOffset( (MiscPixels) nsrect.origin.x );
- *cmax = colBorder->visualForOffset(
- (MiscPixels) (nsrect.origin.x + nsrect.size.width) - 1 );
- *rmin = rowBorder->visualForOffset( (MiscPixels) nsrect.origin.y );
- *rmax = rowBorder->visualForOffset(
- (MiscPixels) (nsrect.origin.y + nsrect.size.height) - 1 );
- }
-
-
- //-----------------------------------------------------------------------------
- // - drawRect:
- //-----------------------------------------------------------------------------
- - (void)drawRect:(NSRect)nsrect
- {
- BOOL const need_clip = ([[self subviews] count] != 0);
- if (need_clip)
- {
- PSgsave();
- NSRectClip( nsrect );
- }
-
- MiscCoord_V c, cmin, cmax, c0, cN;
- MiscCoord_V r, rmin, rmax, r0, rN;
- [self cMin:&cmin cMax:&cmax rMin:&rmin rMax:&rmax forRect:nsrect];
-
- if (cmin >= 0 && cmax >= 0 && rmin >= 0 && rmax >= 0)
- {
- MiscColorList cl;
- id const scroll = [self scroll];
-
- int const NORM_COLOR = cl.store([scroll backgroundColor]) + 1;
- int const HIGH_COLOR = cl.store([scroll selectedBackgroundColor]) + 1;
-
- int const nc = (cmax - cmin) + 1;
- int const nr = (rmax - rmin) + 1;
- int* map = (int*) calloc( nc * nr, sizeof(*map) );
- int* p = map;
-
- for (r = rmin; r <= rmax; r++) // Transparent and ownerDraw
- { // cell backgrounds.
- MiscCoord_P const pr = rowBorder->visualToPhysical(r);
- BOOL const row_lit = rowBorder->isSelected(r);
- for (c = cmin; c <= cmax; c++,p++)
- {
- MiscCoord_P const pc = colBorder->visualToPhysical(c);
- BOOL const lit = row_lit || colBorder->isSelected(c);
- id cell = [scroll cellAtRow:pr column:pc];
- if (cell == 0 || ![cell isOpaque])
- *p = lit ? HIGH_COLOR : NORM_COLOR;
- else if ([cell respondsToSelector:@selector(ownerDraw)] &&
- [cell ownerDraw])
- {
- if (lit && [cell respondsToSelector:
- @selector(selectedBackgroundColor)])
- *p = cl.store( [cell selectedBackgroundColor] ) + 1;
- else if ([cell respondsToSelector:
- @selector(backgroundColor)])
- *p = cl.store( [cell backgroundColor] ) + 1;
- else
- *p = lit ? HIGH_COLOR : NORM_COLOR;
- }
- }
- }
-
- MiscRectColorList rcl;
- NSRect rect;
- int color;
- while ((color = extract_rect( map, nc, nr, c0, r0, cN, rN )) != 0)
- {
- c0 += cmin; cN += cmin;
- r0 += rmin; rN += rmin;
- MiscPixels const x0 = colBorder->getOffset( c0 );
- MiscPixels const y0 = rowBorder->getOffset( r0 );
- MiscPixels const xN = colBorder->getOffset( cN ) +
- colBorder->effectiveSize( cN );
- MiscPixels const yN = rowBorder->getOffset( rN ) +
- rowBorder->effectiveSize( rN );
- rect.origin.x = x0;
- rect.origin.y = y0;
- rect.size.width = (xN - x0);
- rect.size.height = (yN - y0);
-
- rcl.append( rect, cl[ color - 1 ] );
- }
-
- free( map );
-
- MiscPixels x,y;
- MiscPixels const ix0 = colBorder->getOffset( cmin );
- MiscPixels const iy0 = rowBorder->getOffset( rmin );
- MiscPixels const ixN = colBorder->getOffset( cmax ) +
- colBorder->effectiveSize( cmax );
- MiscPixels const iyN = rowBorder->getOffset( rmax ) +
- rowBorder->effectiveSize( rmax );
-
- MiscRectList grid_rl; // Grid drawing list.
- y = iy0; // Horizontal grid lines.
- rect.origin.x = floor( (float) ix0 );
- rect.size.width = floor( (float) (ixN - ix0) );
- rect.size.height = 1;
- for (r = rmin; r <= rmax; r++)
- {
- MiscPixels const h = rowBorder->effectiveSize(r);
- y += h - 1;
- rect.origin.y = floor( (float) y );
- grid_rl.append( rect );
- y++;
- }
-
- x = ix0; // Vertical grid lines.
- rect.origin.y = floor( (float) iy0 );
- rect.size.width = 1;
- rect.size.height = floor( (float) (iyN - iy0) );
- for (c = cmin; c <= cmax; c++)
- {
- MiscPixels const w = colBorder->effectiveSize(c);
- x += w - 1;
- rect.origin.x = floor( (float) x );
- grid_rl.append( rect );
- x++;
- }
-
- rcl.draw();
- grid_rl.draw( [NSColor gridColor] );
-
- NSColor* const fgColor = [scroll textColor];
- NSColor* const hfgColor = [scroll selectedTextColor];
- NSFont* const fnt = [scroll font];
- MiscDrawList dl( [scroll drawClippedText] );
-
- y = iy0; // Cell contents.
- for (r = rmin; r <= rmax; r++)
- {
- MiscCoord_P const pr = rowBorder->visualToPhysical(r);
- BOOL const row_lit = rowBorder->isSelected(r);
- MiscPixels const h = rowBorder->effectiveSize(r);
- rect.origin.y = floor( (float) y );
- rect.size.height = floor( (float) (h - 1) );
- x = ix0;
- for (c = cmin; c <= cmax; c++)
- {
- MiscCoord_P const pc = colBorder->visualToPhysical(c);
- BOOL const lit = row_lit || colBorder->isSelected(c);
- MiscPixels const w = colBorder->effectiveSize(c);
- rect.origin.x = x;
- rect.size.width = (w - 1);
- id cell = [scroll cellAtRow:pr column:pc];
- if (cell == 0 ||
- [cell respondsToSelector:@selector(ownerDraw)] &&
- [cell ownerDraw])
- {
- dl.append( rect, cell, lit,
- (lit ? hfgColor : fgColor), fnt );
- }
- else
- [cell drawWithFrame:rect inView:self];
- x += w;
- }
- y += h;
- }
-
- dl.draw();
- if ([self shouldDrawCursor])
- [self drawCursorClipTo:NSMakeRect(ix0, iy0, ixN - ix0, iyN - iy0)];
- }
-
- if (need_clip)
- PSgrestore();
- }
-
-
- //-----------------------------------------------------------------------------
- // - drawCellAtRow:column: -- Physical coords
- //-----------------------------------------------------------------------------
- - (void)drawCellAtRow:(int)row column:(int)col
- {
- [self drawRect:[self cellFrameAtRow:row column:col]];
- }
-
-
- //-----------------------------------------------------------------------------
- // - drawRow: -- Physical coord
- //-----------------------------------------------------------------------------
- - (void)drawRow:(int)row
- {
- if ([self canDraw] && row >= 0 && row < rowBorder->count())
- {
- MiscCoord_V const vRow = rowBorder->physicalToVisual(row);
- MiscPixels const offset = rowBorder->getOffset(vRow);
- MiscPixels const size = rowBorder->effectiveSize(vRow);
-
- NSRect r = [self visibleRect];
- if (offset + size >= NSMinY(r) && offset < NSMaxY(r))
- {
- r.origin.y = rowBorder->getOffset(vRow);
- r.size.height = rowBorder->effectiveSize(vRow);
- [self setNeedsDisplayInRect:r];
- }
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // - drawColumn: -- Physical coord
- //-----------------------------------------------------------------------------
- - (void)drawColumn:(int)col
- {
- if ([self canDraw] && col >= 0 && col < colBorder->count())
- {
- MiscCoord_V const vCol = colBorder->physicalToVisual(col);
- MiscPixels const offset = colBorder->getOffset(vCol);
- MiscPixels const size = colBorder->effectiveSize(vCol);
-
- NSRect r = [self visibleRect];
- if (offset + size >= NSMinX(r) && offset < NSMaxX(r))
- {
- r.origin.x = colBorder->getOffset(vCol);
- r.size.width = colBorder->effectiveSize(vCol);
- [self setNeedsDisplayInRect:r];
- }
- }
- }
-
-
- //=============================================================================
- // SELECTION
- //=============================================================================
- //-----------------------------------------------------------------------------
- // - setSelectionMode:
- //-----------------------------------------------------------------------------
- - (void)setSelectionMode:(MiscSelectionMode)mode
- {
- NSZone* const z = [self zone];
- if (tracker != 0)
- [tracker release];
- switch (mode)
- {
- case MISC_LIST_MODE:
- tracker = [MiscListTracker allocWithZone:z];
- break;
- case MISC_RADIO_MODE:
- tracker = [MiscRadioTracker allocWithZone:z];
- break;
- case MISC_HIGHLIGHT_MODE:
- tracker = [MiscHighlightTracker allocWithZone:z];
- break;
- }
- [tracker initBorder:[self borderFor:trackerBorder]];
- }
-
-
- //-----------------------------------------------------------------------------
- // - selectionChanged
- //-----------------------------------------------------------------------------
- - (void)selectionChanged
- {
- MiscSparseSet const& newColSel = colBorder->selectionSet();
- MiscSparseSet const& newRowSel = rowBorder->selectionSet();
-
- MiscCoord_V cmin, cmax;
- MiscCoord_V rmin, rmax;
- NSRect vis = [self visibleRect];
- [self cMin:&cmin cMax:&cmax rMin:&rmin rMax:&rmax forRect:vis];
-
- for (MiscCoord_V r = rmin; r <= rmax; r++)
- {
- BOOL rowWasOn = oldRowSel->contains(r);
- BOOL rowIsOn = newRowSel.contains(r);
- for (MiscCoord_V c = cmin; c <= cmax; c++)
- {
- BOOL wasOn = rowWasOn || oldColSel->contains(c);
- BOOL isOn = rowIsOn || newColSel.contains(c);
- if (isOn != wasOn)
- {
- [self setNeedsDisplayInRect:
- NSMakeRect( colBorder->getOffset(c),
- rowBorder->getOffset(r),
- colBorder->effectiveSize(c),
- rowBorder->effectiveSize(r) )];
- }
- }
- }
- *oldColSel = newColSel;
- *oldRowSel = newRowSel;
- }
-
-
- //-----------------------------------------------------------------------------
- // - resetSelection
- //-----------------------------------------------------------------------------
- - (void)resetSelection
- {
- *oldColSel = colBorder->selectionSet();
- *oldRowSel = rowBorder->selectionSet();
- }
-
-
- //-----------------------------------------------------------------------------
- // - trackBy:
- //-----------------------------------------------------------------------------
- - (void)trackBy:(MiscBorderType)b
- {
- trackerBorder = b;
- }
-
-
- //-----------------------------------------------------------------------------
- // - trackingBy
- //-----------------------------------------------------------------------------
- - (MiscBorderType)trackingBy
- {
- return trackerBorder;
- }
-
-
- //=============================================================================
- // MOUSE TRACKING
- //=============================================================================
- //-----------------------------------------------------------------------------
- // - constrainSlot:inBorder:
- //-----------------------------------------------------------------------------
- - (MiscCoord_V)constrainSlot:(MiscCoord_V)s inBorder:(MiscTableBorder*)b
- {
- if (s < 0)
- s = 0;
- else if (s >= b->count())
- s = b->count() - 1;
- return s;
- }
-
-
- //-----------------------------------------------------------------------------
- // - displayNewSelection
- //-----------------------------------------------------------------------------
- - (void)displayNewSelection
- {
- id const scroll = [self scroll];
- [scroll selectionChanged];
- [scroll displayIfNeeded];
- }
-
-
- //-----------------------------------------------------------------------------
- // - sendAction:to:
- //
- // NOTE *1*: Conforms to Control's -sendAction:to: which does *not* send
- // any message if the "action" is null.
- //-----------------------------------------------------------------------------
- - (BOOL)sendAction:(SEL)cmd to:(id)obj
- {
- if (cmd != 0) // NOTE *1*
- return [NSApp sendAction:cmd to:obj from:[self scroll]];
- return NO;
- }
-
-
- //-----------------------------------------------------------------------------
- // - setClickedCellFromEvent:
- //-----------------------------------------------------------------------------
- - (void)setClickedCellFromEvent:(NSEvent*)e
- {
- NSPoint const p = [self convertPoint:[e locationInWindow] fromView:0];
- NSRect b = [self bounds];
- MiscCoord_V const v_row = (p.y < NSMaxY(b) ?
- rowBorder->visualForOffset( (MiscPixels)p.y ) : -1);
- MiscCoord_V const v_col = (p.x < NSMaxX(b) ?
- colBorder->visualForOffset( (MiscPixels)p.x ) : -1);
- MiscCoord_P const p_row = rowBorder->visualToPhysical( v_row );
- MiscCoord_P const p_col = colBorder->visualToPhysical( v_col );
- [[self scroll] setClickedRow:p_row column:p_col];
- }
-
-
- //-----------------------------------------------------------------------------
- // - cellTrackMouse:atRow:column:
- //-----------------------------------------------------------------------------
- - (BOOL)cellTrackMouse:(NSEvent*)p
- atRow:(MiscCoord_V)v_row column:(MiscCoord_V)v_col
- {
- BOOL upInCell = NO;
-
- MiscCoord_P const p_col = colBorder->visualToPhysical( v_col );
- MiscCoord_P const p_row = rowBorder->visualToPhysical( v_row );
-
- NSRect r = [self cellInsideAtRow:p_row column:p_col];
- id const scroll = [self scroll];
-
- id cell = [scroll cellAtRow:p_row column:p_col];
- [scroll setClickedRow:p_row column:p_col];
-
- if ([scroll editIfAble:p atRow:p_row column:p_col])
- upInCell = YES;
- else if ([self canPerformDragAtRow:p_row column:p_col withEvent:p])
- upInCell = [self awaitDragEvent:p atRow:p_row column:p_col inRect:r];
- else if ([cell isEnabled])
- {
- NSWindow* win = [self window];
- [self lockFocus];
- [scroll setTracking:YES];
- [cell setCellAttribute:NSCellHighlighted to:1];
- [scroll drawCellAtRow:p_row column:p_col];
- [win flushWindow];
- upInCell = [cell trackMouse:p inRect:r ofView:self
- untilMouseUp:[[cell class] prefersTrackingUntilMouseUp]];
- [scroll setTracking:NO];
- [cell setCellAttribute:NSCellHighlighted to:0];
- [scroll drawCellAtRow:p_row column:p_col];
- [self unlockFocus];
- [win flushWindow];
- }
-
- return upInCell;
- }
-
-
- //-----------------------------------------------------------------------------
- // - mouseDown:
- //-----------------------------------------------------------------------------
- - (void)mouseDown:(NSEvent*)p
- {
- unsigned int const WANTED =
- (NSLeftMouseUpMask | NSLeftMouseDraggedMask | NSPeriodicMask);
-
- id const scroll = [self scroll];
- BOOL const doubleClicked = ([p clickCount] > 1);
- NSPoint evpt = [self convertPoint:[p locationInWindow] fromView:0];
-
- MiscCoord_V const v_col = colBorder->visualForOffset((MiscPixels)evpt.x);
- MiscCoord_V const v_row = rowBorder->visualForOffset((MiscPixels)evpt.y);
- MiscCoord_V slot = (trackerBorder == MISC_COL_BORDER ? v_col : v_row);
- MiscTableBorder* const b = [self borderFor:trackerBorder];
-
- [self eraseCursor];
- [self disableCursor];
-
- [tracker mouseDown:p atPos:slot];
- [self otherBorder:trackerBorder]->selectNone();
- [self displayNewSelection];
-
- BOOL mouseUpInCell = NO;
- if ([scroll isEnabled])
- mouseUpInCell = [self cellTrackMouse:p atRow:v_row column:v_col];
-
- if (!mouseUpInCell)
- {
- [NSEvent startPeriodicEventsAfterDelay:0.1 withPeriod:0.1];
- NSEvent* lastEvent = [p copy];
-
- for (;;)
- {
- p = [[self window] nextEventMatchingMask:WANTED];
- if (p == 0 || [p type] == NSLeftMouseUp)
- break;
- else if ([p type] == NSPeriodic)
- [self autoscroll:lastEvent];
- else
- {
- [lastEvent release];
- lastEvent = [p copy];
- }
-
- NSPoint new_loc =
- [self convertPoint:[lastEvent locationInWindow] fromView:0];
- MiscPixels const offset =
- MiscPoint_O( trackerBorder, new_loc ).getX_O();
- MiscCoord_V const new_slot =
- offset < MiscRect_O(trackerBorder,[self bounds]).getMaxX_O() ?
- b->visualForOffset(offset) : b->count();
- if (new_slot != slot)
- {
- slot = new_slot;
- [tracker mouseDragged:p atPos:slot];
- [self displayNewSelection];
- }
- }
-
- [lastEvent release];
- [NSEvent stopPeriodicEvents];
- [self setClickedCellFromEvent:p];
- }
-
- [tracker mouseUp:p atPos:slot];
- [self displayNewSelection];
- [scroll border:trackerBorder setCursorSlot:
- b->visualToPhysical([self constrainSlot:slot inBorder:b])];
-
- [self enableCursor];
- if ([self shouldDrawCursor])
- [self drawCursor];
- [[self window] flushWindow];
-
- if ([scroll isEnabled])
- {
- [scroll sendAction];
- if (doubleClicked && ![scroll isEditing]) // FIXME: not right
- [scroll sendDoubleAction];
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // *FIXME*
- // OPENSTEP 4.2 Objective-C++ compiler for NT (final release) crashes
- // whenever a message is sent to 'super' from within a category. This
- // bug also afflicts the 4.2 (prerelease) compiler for Mach and NT.
- // Work around it by providing stub methods in the main (non-category)
- // implementation which merely forward the appropriate message to 'super'
- // on behalf of the categories. Though ugly, it works, is very
- // localized, and simple to remove when the bug is finally fixed.
- //-----------------------------------------------------------------------------
- - (void)superPrint:(id)sender { [super print:sender]; }
-
- @end
-