home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / YellowBox / Kits / MiscTableScroll-138.1 / Palettes / MiscTableScroll / Framework / MiscTableScroll.M < prev    next >
Encoding:
Text File  |  1998-03-31  |  54.5 KB  |  1,699 lines

  1. //=============================================================================
  2. //
  3. //  Copyright (C) 1995,1996,1997,1998 by Paul S. McCarthy and Eric Sunshine.
  4. //        Written by Paul S. McCarthy and Eric Sunshine.
  5. //                All Rights Reserved.
  6. //
  7. //    This notice may not be removed from this source code.
  8. //
  9. //    This object is included in the MiscKit by permission from the authors
  10. //    and its use is governed by the MiscKit license, found in the file
  11. //    "License.rtf" in the MiscKit distribution.  Please refer to that file
  12. //    for a list of all applicable permissions and restrictions.
  13. //
  14. //=============================================================================
  15. //-----------------------------------------------------------------------------
  16. // MiscTableScroll.M
  17. //
  18. //    ScrollView class that displays a 2-D table of cells.
  19. //
  20. //-----------------------------------------------------------------------------
  21. //-----------------------------------------------------------------------------
  22. // $Id: MiscTableScroll.M,v 1.46 98/03/29 23:53:12 sunshine Exp $
  23. // $Log:    MiscTableScroll.M,v $
  24. // Revision 1.46  98/03/29  23:53:12  sunshine
  25. // v138.1: Removed useless 'if' from -borderSetSlotOrder:.
  26. // Fixed bug: Wasn't checking -canDraw before applying -lockFocus in:
  27. // -drawCellAtRow:column:, -drawRow:, -drawColumn:, -drawSlotTitle:.
  28. // Now uses NSColor's "system" colors for text, background, selected text,
  29. // selected background by default.
  30. // Worked around OPENSTEP 4.2 for NT bug where compiler crashes when sending
  31. // a message to 'super' from within a category.  Bug afflicted
  32. // MiscTableScrollIO.M.
  33. // 
  34. // Revision 1.45  98/03/23  21:41:42  sunshine
  35. // v137.1: -border:setSlotOrder: now accepts a null pointer or empty list to
  36. // "unsort" the slots.
  37. //
  38. // Revision 1.44  98/03/23  07:47:10  sunshine
  39. // v134.1: Now uses -suspendEditing / -resumeEditing.
  40. //-----------------------------------------------------------------------------
  41. #import <MiscTableScroll/MiscTableScroll.h>
  42. #import <MiscTableScroll/MiscTableCell.h>
  43. #import "MiscColView.h"
  44. #import "MiscCornerView.h"
  45. #import "MiscRowView.h"
  46. #import "MiscTableBorder.h"
  47. #import "MiscTableScrollPrivate.h"
  48. #import "MiscTableView.h"
  49. #import    <new.h>
  50.  
  51. extern "Objective-C" {
  52. #import <AppKit/NSApplication.h>
  53. #import <AppKit/NSCell.h>
  54. #import <AppKit/NSClipView.h>
  55. #import <AppKit/NSControl.h>    // Control-text notifications
  56. #import <AppKit/NSFont.h>
  57. #import <AppKit/NSFontManager.h>
  58. #import <AppKit/NSScroller.h>
  59. }
  60.  
  61. extern "C" {
  62. #import <math.h>
  63. #import    <strings.h>
  64. }
  65.  
  66. typedef MiscDelegateFlags DF;
  67.  
  68. //-----------------------------------------------------------------------------
  69. // Delegate Notifications
  70. //-----------------------------------------------------------------------------
  71. static NSArray* DEL_NOTIFICATIONS = 0;    // Array of MiscNotification objects.
  72.  
  73. @interface MiscNotification : NSObject
  74.     {
  75.     DF::Selector selector;
  76.     NSString* notification;
  77.     }
  78. + (MiscNotification*)notificationWithSelector:(DF::Selector)s
  79.     notification:(NSString*)n;
  80. - (id)initWithSelector:(DF::Selector)s notification:(NSString*)n;
  81. - (void)dealloc;
  82. - (DF::Selector)selector;
  83. - (NSString*)notification;
  84. @end
  85.  
  86. @implementation MiscNotification
  87. + (MiscNotification*)notificationWithSelector:(DF::Selector)s
  88.     notification:(NSString*)n
  89.     { return [[[self alloc] initWithSelector:s notification:n] autorelease]; }
  90. - (id)initWithSelector:(DF::Selector)s notification:(NSString*)n
  91.     { [super init]; selector = s; notification = [n retain]; return self; }
  92. - (void)dealloc { [notification release]; [super dealloc]; }
  93. - (DF::Selector)selector { return selector; }
  94. - (NSString*)notification { return notification; }
  95. @end
  96.  
  97.  
  98. //=============================================================================
  99. // IMPLEMENTATION
  100. //=============================================================================
  101. @implementation MiscTableScroll
  102.  
  103. - (int)tag        { return tag; }
  104. - (void)setTag:(int)x    { tag = x; }
  105.  
  106. //-----------------------------------------------------------------------------
  107. // + initialize
  108. //-----------------------------------------------------------------------------
  109. + (void)initialize
  110.     {
  111.     if (self == [MiscTableScroll class])
  112.     {
  113.     [self setVersion:MISC_TS_VERSION];
  114.     #define NOTIFY(X,Y) \
  115.         [MiscNotification notificationWithSelector:(DF::DEL_TEXT_ ## X) \
  116.         notification:Y]
  117.     DEL_NOTIFICATIONS = [[NSArray arrayWithObjects:
  118.         NOTIFY( DID_END, NSControlTextDidEndEditingNotification ),
  119.         NOTIFY( DID_CHANGE, NSControlTextDidBeginEditingNotification ),
  120.         NOTIFY( DID_GET_KEYS, NSControlTextDidChangeNotification ), 0]
  121.         retain];
  122.     #undef NOTIFY
  123.     }
  124.     }
  125.  
  126.  
  127. //-----------------------------------------------------------------------------
  128. // Multicast Messages
  129. //-----------------------------------------------------------------------------
  130. - (void)sendAction:(SEL)aSel to:(id)obj forAllCells:(BOOL)flag
  131.     {
  132.     int const rlim = num_rows;
  133.     int const clim = num_cols;
  134.     for (int r = 0;  r < rlim;  r++)
  135.     for (int c = 0;  c < clim;  c++)
  136.         if (flag || [self cellIsSelectedAtRow:r column:c])
  137.         if (![obj performSelector:aSel
  138.             withObject:[self cellAtRow:r column:c]])
  139.             break;
  140.     }
  141.  
  142. - (int)makeCellsPerformSelector:(SEL)s with:(id)p1 with:(id)p2
  143.     selectedOnly:(BOOL)f
  144.     {
  145.     int count = 0;
  146.     int const rlim = num_rows;
  147.     int const clim = num_cols;
  148.     for (int r = 0;  r < rlim;  r++)
  149.     for (int c = 0;  c < clim;  c++)
  150.         if (!f || [self cellIsSelectedAtRow:r column:c])
  151.         {
  152.         id cell = [self cellAtRow:r column:c];
  153.         if ([cell respondsToSelector:s])
  154.             if ([cell performSelector:s
  155.             withObject:p1 withObject:p2])
  156.             count++;
  157.             else
  158.             return count;
  159.         }
  160.     return count;
  161.     }
  162.  
  163. - (int)makeCellsPerformSelector:(SEL)aSel with:(id)p1 selectedOnly:(BOOL)flag
  164.     { return [self makeCellsPerformSelector:aSel with:p1 with:0
  165.     selectedOnly:flag]; }
  166. - (int)makeCellsPerformSelector:(SEL)aSel selectedOnly:(BOOL)flag
  167.     { return [self makeCellsPerformSelector:aSel with:0 with:0
  168.     selectedOnly:flag]; }
  169.  
  170. - (int)makeCellsPerformSelector:(SEL)aSel
  171.     { return [self makeCellsPerformSelector:aSel selectedOnly:NO]; }
  172. - (int)makeCellsPerformSelector:(SEL)aSel with:(id)p1
  173.     { return [self makeCellsPerformSelector:aSel with:p1 selectedOnly:NO]; }
  174. - (int)makeCellsPerformSelector:(SEL)aSel with:(id)p1 with:(id)p2
  175.     { return [self makeCellsPerformSelector:aSel with:p1 with:p2
  176.     selectedOnly:NO];}
  177.  
  178.  
  179. //-----------------------------------------------------------------------------
  180. // FINDING CELLS
  181. //-----------------------------------------------------------------------------
  182. - (int)border:(MiscBorderType)b slotWithTag:(int)x
  183.     {
  184.     int const lim = (int) [self numberOfSlots:b];
  185.     for (int i = 0;  i < lim;  i++)
  186.         if ([self border:b slotTag:i] == x)
  187.         return i;
  188.     return -1;
  189.     }
  190. - (int)columnWithTag:(int)x
  191.     { return [self border:MISC_COL_BORDER slotWithTag:x]; }
  192. - (int)rowWithTag:(int)x
  193.     { return [self border:MISC_ROW_BORDER slotWithTag:x]; }
  194.  
  195. - (BOOL)getRow:(int*)row column:(int*)col ofCell:(NSCell*)cell
  196.     {
  197.     int const NRows = [self numberOfRows];
  198.     int const NCols = [self numberOfColumns];
  199.     for (int r = 0;  r < NRows;  r++)
  200.     for (int c = 0;  c < NCols;  c++)
  201.         if ([self cellAtRow:r column:c] == cell)
  202.         {
  203.         *row = r;
  204.         *col = c;
  205.         return YES;
  206.         }
  207.     *row = -1;
  208.     *col = -1;
  209.     return NO;
  210.     }
  211.  
  212. - (BOOL)getRow:(int*)row column:(int*)col ofCellWithTag:(int)x
  213.     {
  214.     int const NRows = [self numberOfRows];
  215.     int const NCols = [self numberOfColumns];
  216.     for (int r = 0;  r < NRows;  r++)
  217.     for (int c = 0;  c < NCols;  c++)
  218.         {
  219.         id const cell = [self cellAtRow:r column:c];
  220.         if (cell && [cell respondsToSelector:@selector(tag)] &&
  221.         [cell tag] == x)
  222.         {
  223.         *row = r;
  224.         *col = c;
  225.         return YES;
  226.         }
  227.         }
  228.     *row = -1;
  229.     *col = -1;
  230.     return NO;
  231.     }
  232.  
  233. - (id)cellWithTag:(int)x
  234.     {
  235.     int r, c;
  236.     return ([self getRow:&r column:&c ofCellWithTag:x] ?
  237.         [self cellAtRow:r column:c] : 0);
  238.     }
  239.  
  240.  
  241. //-----------------------------------------------------------------------------
  242. // - documentClipRect
  243. //-----------------------------------------------------------------------------
  244. - (NSRect)documentClipRect { return [[self contentView] frame]; }
  245.  
  246.  
  247. //-----------------------------------------------------------------------------
  248. // Delegate Stuff
  249. //-----------------------------------------------------------------------------
  250. - (void)registerDelegateNotifications:(id)del
  251.     flags:(MiscDelegateFlags const*)flags
  252.     {
  253.     NSNotificationCenter* const nc = [NSNotificationCenter defaultCenter];
  254.     for (unsigned int i = [DEL_NOTIFICATIONS count]; i-- > 0; )
  255.     {
  256.     MiscNotification* const n = [DEL_NOTIFICATIONS objectAtIndex:i];
  257.     DF::Selector const s = [n selector];
  258.     if (flags->respondsTo(s))
  259.         [nc addObserver:del selector:flags->selToObjc(s)
  260.             name:[n notification] object:tableView];
  261.     }
  262.     }
  263.  
  264. - (void)cancelDelegateNotifications:(id)del
  265.     flags:(MiscDelegateFlags const*)flags
  266.     {
  267.     NSNotificationCenter* const nc = [NSNotificationCenter defaultCenter];
  268.     for (unsigned int i = [DEL_NOTIFICATIONS count]; i-- > 0; )
  269.     {
  270.     MiscNotification* const n = [DEL_NOTIFICATIONS objectAtIndex:i];
  271.     if (flags->respondsTo( [n selector] ))
  272.         [nc removeObserver:del name:[n notification] object:tableView];
  273.     }
  274.     }
  275.  
  276. - (void)replaceDelegate:(id*)old_del with:(id)new_del
  277.     flags:(MiscDelegateFlags*)flags
  278.     {
  279.     if (*old_del != 0)
  280.     [self cancelDelegateNotifications:*old_del flags:flags];
  281.     *old_del = new_del;
  282.     flags->setDelegate( new_del );
  283.     if (new_del != 0)
  284.     [self registerDelegateNotifications:new_del flags:flags];
  285.     }
  286.  
  287. - (id)delegate            { return delegate; }
  288. - (id)dataDelegate        { return dataDelegate; }
  289. - (void)setDelegate:(id)obj
  290.     { [self replaceDelegate:&delegate with:obj flags:delegateFlags]; }
  291. - (void)setDataDelegate:(id)obj
  292.     { [self replaceDelegate:&dataDelegate with:obj flags:dataDelegateFlags]; }
  293.  
  294. - (id)responsibleDelegate:(DF::Selector)cmd
  295.     {
  296.     id del = 0;
  297.     if (delegate != 0 && delegateFlags->respondsTo(cmd))
  298.     del = delegate;
  299.     else if (dataDelegate != 0 && dataDelegateFlags->respondsTo(cmd))
  300.     del = dataDelegate;
  301.     return del;
  302.     }
  303.  
  304.  
  305. //-----------------------------------------------------------------------------
  306. // - freeBorder:
  307. //-----------------------------------------------------------------------------
  308. - (void)freeBorder:(MiscBorderInfo*)p
  309.     {
  310.     [p->view removeFromSuperview];
  311.     [p->view release];
  312.     [p->clip removeFromSuperview];
  313.     [p->clip release];
  314.     delete p->border;
  315.     }
  316.  
  317.  
  318. //-----------------------------------------------------------------------------
  319. // - dealloc
  320. //-----------------------------------------------------------------------------
  321. - (void)dealloc
  322.     {
  323.     NSWindow* win = [self window];
  324.     if (win != 0 && [win firstResponder] == tableView)
  325.     [win makeFirstResponder:win];
  326.     [self emptyAndReleaseCells];
  327.     [cornerView removeFromSuperview];
  328.     [cornerView release];
  329.     [tableView removeFromSuperview];
  330.     [tableView release];
  331.     [self freeBorder:&colInfo];
  332.     [self freeBorder:&rowInfo];
  333.     if (delegate != 0)
  334.     [self cancelDelegateNotifications:delegate flags:delegateFlags];
  335.     if (dataDelegate != 0)
  336.     [self cancelDelegateNotifications:dataDelegate flags:dataDelegateFlags];
  337.     delete delegateFlags;
  338.     delete dataDelegateFlags;
  339.     [super dealloc];
  340.     }
  341.  
  342.  
  343. //-----------------------------------------------------------------------------
  344. // - totalSize / totalWidth / totalHeight
  345. //-----------------------------------------------------------------------------
  346. - (float)totalSize:(MiscBorderType)b
  347.     { return (float) info[b]->border->totalSize(); }
  348. - (float)totalWidth
  349.     { return [self totalSize:MISC_COL_BORDER]; }
  350. - (float)totalHeight
  351.     { return [self totalSize:MISC_ROW_BORDER]; }
  352.  
  353.  
  354. //-----------------------------------------------------------------------------
  355. // - constrainSize
  356. //-----------------------------------------------------------------------------
  357. - (void)constrainSize
  358.     {
  359.     MiscTableBorder* b;
  360.     NSRect r = [self documentClipRect];
  361.  
  362.     b = colInfo.border;
  363.     if (b->numSpringy() != 0)
  364.     b->setMinTotalSize( (MiscPixels) r.size.width );
  365.  
  366.     b = rowInfo.border;
  367.     if (b->numSpringy() != 0)
  368.     b->setMinTotalSize( (MiscPixels) r.size.height );
  369.  
  370.     [rowInfo.view adjustSize];
  371.     [colInfo.view adjustSize];
  372.     [tableView adjustSize];
  373.     }
  374.  
  375.  
  376. //-----------------------------------------------------------------------------
  377. // - sizeToCells
  378. //-----------------------------------------------------------------------------
  379. - (void)sizeToCells
  380.     {
  381.     [self constrainSize];
  382.     }
  383.  
  384.  
  385. //-----------------------------------------------------------------------------
  386. // set_sizes
  387. //-----------------------------------------------------------------------------
  388. static void set_sizes( MiscTableBorder* b, float const* v, float lim )
  389.     {
  390.     int const n = b->count();
  391.     if (!b->isUniformSize())
  392.     {
  393.     for (int i = 0; i < n; i++)
  394.         {
  395.         MiscPixels x = (MiscPixels) v[i];
  396.         MiscPixels const xmin = b->getMinSize_P(i);
  397.         MiscPixels const xmax = b->getMaxSize_P(i);
  398.         if (x < xmin) x = xmin;
  399.         if (x > xmax) x = xmax;
  400.         b->setSize_P( i, (MiscPixels) x );
  401.         }
  402.     }
  403.     else if (lim != 0)
  404.     b->setUniformSize( (MiscPixels) lim );
  405.     }
  406.  
  407.  
  408. //-----------------------------------------------------------------------------
  409. // - sizeToFit
  410. //-----------------------------------------------------------------------------
  411. - (void)sizeToFit
  412.     {
  413.     float* const vw = (float*)calloc( (num_rows + num_cols), sizeof(*vw) );
  414.     float* const vh = vw + num_cols;
  415.     float max_h = 0;
  416.     float max_w = 0;
  417.     for (int r = 0; r < num_rows; r++)
  418.     {
  419.     float h = 0;
  420.     for (int c = 0; c < num_cols; c++)
  421.         {
  422.         id const cell = [self cellAtRow:r column:c];
  423.         if (cell != 0 && [cell respondsToSelector:@selector(cellSize:)])
  424.         {
  425.         NSSize const sz = [cell cellSize];
  426.         if (vw[c] < sz.width) vw[c] = sz.width;
  427.         if (max_w < sz.width) max_w = sz.width;
  428.         if (h < sz.height) h = sz.height;
  429.         }
  430.         }
  431.     if (vh[r] < h) vh[r] = h;
  432.     if (max_h < h) max_h = h;
  433.     }
  434.  
  435.     set_sizes( colInfo.border, vw, max_w );
  436.     set_sizes( rowInfo.border, vh, max_h );
  437.     free( vw );
  438.  
  439.     [self sizeToCells];
  440.     }
  441.  
  442.  
  443. //-----------------------------------------------------------------------------
  444. // - setFrameSize:
  445. //-----------------------------------------------------------------------------
  446. - (void)setFrameSize:(NSSize)s
  447.     {
  448.     [super setFrameSize:s];
  449.     [self constrainSize];
  450.     }
  451.  
  452.  
  453. //-----------------------------------------------------------------------------
  454. // - forwardBGColor
  455. //-----------------------------------------------------------------------------
  456. - (void)forwardBGColor
  457.     {
  458.     [super setBackgroundColor:backgroundColor];
  459.     [colInfo.clip setBackgroundColor:backgroundColor];
  460.     [rowInfo.clip setBackgroundColor:backgroundColor];
  461.     }
  462.  
  463.  
  464. //-----------------------------------------------------------------------------
  465. // - initBorder:type:
  466. //-----------------------------------------------------------------------------
  467. - (void)initBorder:(MiscBorderInfo*)p type:(MiscBorderType)type
  468.     {
  469.     NSZone* const z = [self zone];
  470.     if (p->border == 0)
  471.     p->border = new( NSZoneMalloc(z,sizeof(*(p->border))) )
  472.             MiscTableBorder( type );
  473.     p->border->setOwner( self );
  474.  
  475.     if (type == MISC_COL_BORDER)
  476.     p->view = [[MiscColView allocWithZone:z]
  477.             initWithFrame:NSZeroRect scroll:self info:p->border];
  478.     else
  479.     p->view = [[MiscRowView allocWithZone:z]
  480.             initWithFrame:NSZeroRect scroll:self info:p->border];
  481.  
  482.     p->clip = [[NSClipView allocWithZone:z] initWithFrame:NSZeroRect];
  483.     [p->clip setDocumentView:p->view];
  484.     if (p->isOn)
  485.     {
  486.     [self addSubview:p->clip];
  487.     [[self window] invalidateCursorRectsForView:p->view];
  488.     }
  489.     }
  490.  
  491.  
  492. //-----------------------------------------------------------------------------
  493. // - doInit:cornerTitle:
  494. //-----------------------------------------------------------------------------
  495. - (void)doInit:(int)ver cornerTitle:(NSString*)s
  496.     {
  497.     editInfo.editing = NO;
  498.     tracking = NO;
  499.  
  500.     [self setBorderType:NSBezelBorder];
  501.     [super setHasHorizontalScroller:YES];
  502.     [super setHasVerticalScroller:YES];
  503.  
  504.     info[ MISC_COL_BORDER ] = &colInfo;
  505.     info[ MISC_ROW_BORDER ] = &rowInfo;
  506.  
  507.     [self initBorder:&colInfo type:MISC_COL_BORDER];
  508.     [self initBorder:&rowInfo type:MISC_ROW_BORDER];
  509.  
  510.     NSZone* const z = [self zone];
  511.  
  512.     delegateFlags =
  513.     new( NSZoneMalloc(z,sizeof(*delegateFlags)) ) MiscDelegateFlags;
  514.     dataDelegateFlags =
  515.     new( NSZoneMalloc(z,sizeof(*dataDelegateFlags)) ) MiscDelegateFlags;
  516.  
  517.     tableView = [[MiscTableView allocWithZone:z] initWithFrame:NSZeroRect
  518.         scroll:self colInfo:colInfo.border rowInfo:rowInfo.border];
  519.  
  520.     cornerView = [[MiscCornerView allocWithZone:z] initWithFrame:NSZeroRect];
  521.     [self setCornerTitle:s];
  522.  
  523.     if (colInfo.isOn && rowInfo.isOn)
  524.     [self addSubview:cornerView];
  525.  
  526.     [self setDocumentView:tableView];
  527.     [self tile];
  528.     [self constrainSize];
  529.     [self forwardBGColor];
  530.  
  531.     [self registerServicesTypes];
  532.     }
  533.  
  534.  
  535. //-----------------------------------------------------------------------------
  536. // - initWithFrame:
  537. //-----------------------------------------------------------------------------
  538. - (id)initWithFrame:(NSRect)frameRect
  539.     {
  540.     [super initWithFrame:frameRect];
  541.  
  542.     tag = 0;
  543.     enabled = YES;
  544.  
  545.     colInfo.border = 0;
  546.     colInfo.isOn = YES;
  547.  
  548.     rowInfo.border = 0;
  549.     rowInfo.isOn = NO;
  550.  
  551.     id classObj = [self class];
  552.     font = [[classObj defaultFont] retain];
  553.     textColor = [[classObj defaultTextColor] retain];
  554.     backgroundColor = [[classObj defaultBackgroundColor] retain];
  555.     selectedTextColor = [[classObj defaultSelectedTextColor] retain];
  556.     selectedBackgroundColor =
  557.         [[classObj defaultSelectedBackgroundColor] retain];
  558.  
  559.     [self doInit:MISC_TS_VERSION cornerTitle:@""];
  560.     return self;
  561.     }
  562.  
  563.  
  564. //-----------------------------------------------------------------------------
  565. // - setFrame:
  566. //-----------------------------------------------------------------------------
  567. - (void)setFrame:(NSRect)frameRect
  568.     {
  569.     [super setFrame:frameRect];
  570.     [self constrainSize];
  571.     }
  572.  
  573.  
  574. //-----------------------------------------------------------------------------
  575. // - tile
  576. //-----------------------------------------------------------------------------
  577. - (void)tile
  578.     {
  579.     static NSClipView* dummy = 0;
  580.     if (dummy == 0)
  581.     dummy = [[NSClipView alloc] initWithFrame:NSZeroRect];
  582.  
  583.     NSClipView* const old = [self contentView];
  584.     _contentView = dummy;
  585.     [super tile];
  586.     _contentView = old;
  587.  
  588.     NSRect docRect = [dummy frame];
  589.  
  590.     if (colInfo.isOn != rowInfo.isOn)        // One on, one off.
  591.     {
  592.     MiscBorderInfo& b = (colInfo.isOn ? colInfo : rowInfo);
  593.     NSRectEdge const edge = (colInfo.isOn ? NSMinYEdge : NSMinXEdge);
  594.     float height = [b.view frameHeight];
  595.     NSRect rect;
  596.  
  597.     NSDivideRect( docRect, &rect, &docRect, height, edge );
  598.  
  599.     [b.clip setFrame:rect];
  600.     [[self contentView] setFrame:docRect];
  601.     [[self window] invalidateCursorRectsForView:b.view];
  602.     }
  603.     else if (colInfo.isOn && rowInfo.isOn)    // Both on.
  604.     {
  605.     float colHeight = [colInfo.view frameHeight];
  606.     float rowWidth  = [rowInfo.view frameHeight];
  607.     NSRect gapRect;
  608.     NSRect colRect;
  609.     NSRect rowRect;
  610.  
  611.     NSDivideRect( docRect, &colRect, &docRect, colHeight, NSMinYEdge );
  612.     NSDivideRect( colRect, &gapRect, &colRect, rowWidth,  NSMinXEdge );
  613.     NSDivideRect( docRect, &rowRect, &docRect, rowWidth,  NSMinXEdge );
  614.  
  615.     [cornerView setFrame:gapRect];
  616.     [colInfo.clip setFrame:colRect];
  617.     [rowInfo.clip setFrame:rowRect];
  618.     [[self contentView] setFrame:docRect];
  619.     [[self window] invalidateCursorRectsForView:colInfo.view];
  620.     [[self window] invalidateCursorRectsForView:rowInfo.view];
  621.     }
  622.     else                    // Both off.
  623.     {
  624.     [[self contentView] setFrame:docRect];
  625.     }
  626.     }
  627.  
  628.  
  629. //-----------------------------------------------------------------------------
  630. // - reflectScroll:
  631. //-----------------------------------------------------------------------------
  632. - (void)reflectScrolledClipView:(NSClipView*)aView
  633.     {
  634.     if (aView == [self contentView]) // only reflect position of contentView
  635.     [super reflectScrolledClipView:aView];
  636.     }
  637.  
  638.  
  639. //-----------------------------------------------------------------------------
  640. // - scrollClip:to:
  641. //-----------------------------------------------------------------------------
  642. - (void)scrollClipView:(NSClipView*)aClipView toPoint:(NSPoint)aPoint
  643.     {
  644.     if (aClipView == [self contentView])    // contentView only.
  645.     {
  646.     NSRect rect;
  647.     NSWindow* win = [self window];
  648.     [win disableFlushWindow];
  649.  
  650.     [aClipView scrollToPoint:aPoint];        // Scroll content
  651.  
  652.     if (colInfo.isOn)
  653.         {
  654.         rect = [colInfo.clip bounds];    // Maybe scroll col headings.
  655.         if (rect.origin.x != aPoint.x)
  656.         {
  657.         rect.origin.x = aPoint.x;
  658.         [colInfo.clip scrollToPoint:rect.origin];
  659.         [[self window] invalidateCursorRectsForView:colInfo.view];
  660.         }
  661.         }
  662.  
  663.     if (rowInfo.isOn)
  664.         {
  665.         rect = [rowInfo.clip bounds];    // Maybe scroll row labels.
  666.         if (rect.origin.y != aPoint.y)
  667.         {
  668.         rect.origin.y = aPoint.y;
  669.         [rowInfo.clip scrollToPoint:rect.origin];
  670.         [[self window] invalidateCursorRectsForView:rowInfo.view];
  671.         }
  672.         }
  673.  
  674.     [win enableFlushWindow];
  675.     [win flushWindow];
  676.     }
  677.     else
  678.     {
  679.     BOOL ok = YES;
  680.     NSView* const cv = [self contentView];
  681.     NSRect rect = [cv bounds];
  682.     if (aClipView == (id)colInfo.clip)
  683.         rect.origin.x = aPoint.x;
  684.     else if (aClipView == (id)rowInfo.clip)
  685.         rect.origin.y = aPoint.y;
  686.     else
  687.         ok = NO;
  688.     if (ok)
  689.         {
  690.         [self scrollClipView:cv toPoint:rect.origin];
  691.         [self reflectScrolledClipView:cv];
  692.         }
  693.     }
  694.     }
  695.  
  696.  
  697. //-----------------------------------------------------------------------------
  698. // Border stuff
  699. //-----------------------------------------------------------------------------
  700. - (NSString*)border:(MiscBorderType)b getDelegateSlotTitle:(int)slot
  701.     {
  702.     id del = [self responsibleDelegate:DF::DEL_SLOT_TITLE];
  703.     if (del != 0)
  704.     return [del tableScroll:self border:b slotTitle:slot];
  705.  
  706.     NSString* s = @"";
  707.     return s;
  708.     }
  709.  
  710. - (id)border:(MiscBorderType)b getDelegateSlotPrototype:(int)s
  711.     {
  712.     id del = [self responsibleDelegate:DF::DEL_SLOT_PROTOTYPE];
  713.     if (del != 0)
  714.     return [del tableScroll:self border:b slotPrototype:s];
  715.     return 0;
  716.     }
  717.  
  718. - (void)border:(MiscBorderType)b slotDraggedFrom:(int)fromPos to:(int)toPos
  719.     {
  720.     MiscBorderType const ob = otherBorder(b);
  721.     if ([self autoSortSlots:ob])
  722.     {
  723.     int const slot = [self border:b slotAtPosition:toPos];
  724.     if ([self border:b slotSortType:slot] != MISC_SORT_SKIP ||
  725.         [self border:b slotSortFunction:slot] != 0)
  726.         [self sortSlots:ob]; // Don't resort if it doesn't affect ordering.
  727.     }
  728.     id del = [self responsibleDelegate:DF::DEL_SLOT_DRAGGED];
  729.     if (del != 0)
  730.     [del tableScroll:self border:b slotDraggedFrom:fromPos to:toPos];
  731.     }
  732.  
  733. - (void)border:(MiscBorderType)b slotSortReversed:(int)n
  734.     {
  735.     MiscBorderType const ob = otherBorder(b);
  736.     if ([self autoSortSlots:ob])
  737.     [self sortSlots:ob];        // Assume it affects sorting.
  738.     id del = [self responsibleDelegate:DF::DEL_SLOT_REVERSED];
  739.     if (del != 0)
  740.     {
  741.     int const phys = [self border:b slotAtPosition:n];
  742.     [del tableScroll:self border:b slotSortReversed:phys];
  743.     }
  744.     }
  745.  
  746. - (void)border:(MiscBorderType)b slotResized:(int)n
  747.     {
  748.     id del = [self responsibleDelegate:DF::DEL_SLOT_RESIZED];
  749.     if (del != 0)
  750.     {
  751.     int const phys = [self border:b slotAtPosition:n];
  752.     [del tableScroll:self border:b slotResized:phys];
  753.     }
  754.     }
  755.  
  756.  
  757. //-----------------------------------------------------------------------------
  758. // Target / Action
  759. //-----------------------------------------------------------------------------
  760. - (id)target                { return target; }
  761. - (void)setTarget:(id)obj        { target = obj; }
  762. - (id)doubleTarget            { return doubleTarget; }
  763. - (void)setDoubleTarget:(id)obj        { doubleTarget = obj; }
  764. - (SEL)action                { return action; }
  765. - (void)setAction:(SEL)new_sel        { action = new_sel; }
  766. - (void)setDoubleAction:(SEL)new_sel    { doubleAction = new_sel; }
  767. - (SEL)doubleAction            { return doubleAction; }
  768.  
  769. - (BOOL)sendAction:(SEL)aSel to:(id)obj
  770.     {
  771.     if (aSel == 0)
  772.         aSel = action;
  773.     if (obj == 0)
  774.         obj = target;
  775.     return [NSApp sendAction:aSel to:obj from:self];
  776.     }
  777.  
  778. - (BOOL)sendAction
  779.     { return [self sendAction:action to:target]; }
  780.  
  781. - (BOOL)sendDoubleAction
  782.     { return [self sendAction:doubleAction to:doubleTarget]; }
  783.  
  784. - (BOOL)sendActionIfEnabled
  785.     {
  786.     if ([self isEnabled]) { [self sendAction]; return YES; }
  787.     return NO;
  788.     }
  789.  
  790. - (BOOL)sendDoubleActionIfEnabled
  791.     {
  792.     if ([self isEnabled]) { [self sendDoubleAction]; return YES; }
  793.     return NO;
  794.     }
  795.  
  796.  
  797. //-----------------------------------------------------------------------------
  798. // FONT
  799. //-----------------------------------------------------------------------------
  800. + (NSFont*)defaultFont { return [NSFont userFontOfSize:12.0]; }
  801. - (NSFont*)font { return font; }
  802.  
  803.  
  804. static double get_height( NSFont* font )
  805.     {
  806.     double const LINE_SPACING = 1.20;
  807.     double const size = [font pointSize];
  808.     return size * LINE_SPACING;
  809.     }
  810.  
  811.  
  812. - (void)setFont:(NSFont*)newFont
  813.     {
  814.     if (![newFont isEqual:font])
  815.     {
  816.     NSFont* oldFont = [font autorelease];
  817.     font = [newFont retain];
  818.     float old_size = [self uniformSizeRows];
  819.     if (old_size != 0)
  820.         {
  821.         // FIXME: Handle this better.  Different cell-types will have
  822.         // different amounts of "fixed-size" border stuff.
  823.         float const BORDER_THICKNESS = 1;
  824.         old_size -= BORDER_THICKNESS;
  825.         float const new_size =
  826.         floor(    0.5 + (double(old_size) *
  827.             (get_height( newFont ) / get_height( oldFont ))));
  828.         if (new_size != old_size)
  829.         [self setUniformSizeRows:(new_size + BORDER_THICKNESS)];
  830.         }
  831.     // FIXME: Set font in all existing prototype cells.
  832.     // WARNING: Currently, just asking the border for a prototype
  833.     // in a given slot allocates and initializes an array of prototypes.
  834.     if (![self isLazy])        // Eager beaver sets all cells now.
  835.         {
  836.         int const NRows = num_rows;
  837.         int const NCols = num_cols;
  838.         for (int r = 0;  r < NRows;  r++)
  839.         {
  840.         for (int c = 0;  c < NCols;  c++)
  841.             {
  842.             id cell = [self cellAtRow:r column:c];
  843.             if (cell != 0)
  844.             {
  845.             if ([cell respondsToSelector:@selector(setOwnerFont:)])
  846.                 [cell setOwnerFont:newFont];
  847.             else if ([cell respondsToSelector:@selector(setFont:)])
  848.                 [cell setFont:newFont];
  849.             }
  850.             }
  851.         }
  852.         }
  853.     id del = [self responsibleDelegate:DF::DEL_FONT_CHANGED];
  854.     if (del != 0)
  855.         [del tableScroll:self fontChangedFrom:oldFont to:newFont];
  856.  
  857.     [self setNeedsDisplay:YES];
  858.     }
  859.     }
  860.  
  861.  
  862. - (void)changeFont:(id)sender
  863.     {
  864.     NSFontManager* fontMgr = [NSFontManager sharedFontManager];
  865.     NSFont* newFont = [fontMgr convertFont:[fontMgr selectedFont]];
  866.     if (newFont != 0 && ![newFont isEqual:font])
  867.     {
  868.     [self suspendEditing];
  869.     NSFont* oldFont = [[font retain] autorelease];
  870.     [self setFont:newFont];
  871.     id del = [self responsibleDelegate:DF::DEL_CHANGE_FONT];
  872.     if (del != 0)
  873.         [del tableScroll:self changeFont:oldFont to:newFont];
  874.     if (editInfo.editing)
  875.         [editInfo.cell setFont:newFont];
  876.     [self resumeEditing];
  877.     }
  878.     }
  879.  
  880.  
  881. //-----------------------------------------------------------------------------
  882. // COLOR
  883. //
  884. // The following macros expand into the implementations for these functions.
  885. // Their names are listed so they can be found when searched for.
  886. // setBackgroundColor:, setTextColor:, setSelectedBackgroundColor:,
  887. // setSelectedTextColor:
  888. //-----------------------------------------------------------------------------
  889. + (NSColor*)defaultBackgroundColor
  890.     { return [NSColor controlBackgroundColor];}
  891. + (NSColor*)defaultTextColor
  892.     { return [NSColor controlTextColor]; }
  893. + (NSColor*)defaultSelectedBackgroundColor
  894.     { return [NSColor selectedControlColor]; }
  895. + (NSColor*)defaultSelectedTextColor
  896.     { return [NSColor selectedControlTextColor]; }
  897.  
  898. - (NSColor*)backgroundColor        { return backgroundColor; }
  899. - (NSColor*)textColor            { return textColor; }
  900. - (NSColor*)selectedBackgroundColor    { return selectedBackgroundColor; }
  901. - (NSColor*)selectedTextColor        { return selectedTextColor; }
  902.  
  903. - (void)setColor:(NSColor*)value    { [self setBackgroundColor:value]; }
  904. - (NSColor*)color            { return [self backgroundColor]; }
  905.  
  906. - (void)setColor:(NSColor*)x        // New color value
  907.     var:(NSColor**)v        // Instance variable for the color
  908.     sel1:(SEL)sel1            // "setOwner...Color:" message for cell
  909.     sel2:(SEL)sel2            // "set...Color:" message for cell
  910.     notifySel:(DF::Selector)notifySel // "..ColorChangedTo:"
  911.     {
  912.     if (![x isEqual:*v])
  913.     {
  914.     [*v autorelease];
  915.     *v = [x retain];
  916.     if (v == &backgroundColor) [self forwardBGColor];
  917.  
  918.     if (![self isLazy])
  919.         {
  920.         int const NRows = num_rows;
  921.         int const NCols = num_cols;
  922.         for (int r = 0; r < NRows;  r++)
  923.         for (int c = 0;  c < NCols;  c++)
  924.             {
  925.             id cell = [self cellAtRow:r column:c];
  926.             if (cell != 0)
  927.             {
  928.             if ([cell respondsToSelector:sel1])
  929.                 (*[cell methodForSelector:sel1])( cell, sel1, x );
  930.             else if ([cell respondsToSelector:sel2])
  931.                 (*[cell methodForSelector:sel2])( cell, sel2, x );
  932.             }
  933.             }
  934.         }
  935.  
  936.     id del = [self responsibleDelegate:notifySel];
  937.     if (del != 0)
  938.         {
  939.         SEL objcSel = DF::selToObjc( notifySel );
  940.         (*[del methodForSelector:objcSel])( del, objcSel, self, x );
  941.         }
  942.  
  943.     [self setNeedsDisplay:YES];
  944.     }
  945.     }
  946.  
  947.  
  948. #define MISC_SET_COLOR_FUNC(LNAME,CNAME,UNAME)\
  949. - (void)set##CNAME##Color:(NSColor*)value\
  950.     { [self setColor:value\
  951.         var:& LNAME##Color\
  952.         sel1:@selector(setOwner##CNAME##Color:)\
  953.         sel2:@selector(set##CNAME##Color:)\
  954.         notifySel:DF::DEL_##UNAME##_COLOR_CHANGED]; }
  955.  
  956. MISC_SET_COLOR_FUNC( background, Background, BACK )
  957. MISC_SET_COLOR_FUNC( text, Text, TEXT )
  958. MISC_SET_COLOR_FUNC( selectedBackground, SelectedBackground, BACK_SEL )
  959. MISC_SET_COLOR_FUNC( selectedText, SelectedText, TEXT_SEL )
  960. #undef MISC_SET_COLOR_FUNC
  961.  
  962.  
  963. //=============================================================================
  964. // SAVE / RESTORE
  965. //=============================================================================
  966.  
  967. - (NSString*)stringFromIntArray:(NSArray*)array
  968.     {
  969.     NSMutableString* s = [[[NSMutableString alloc] init] autorelease];
  970.     for (int i = 0, lim = [array count]; i < lim; i++)
  971.     {
  972.     if (i > 0) [s appendString:@" "];
  973.     [s appendString:[[array objectAtIndex:i] stringValue]];
  974.     }
  975.     return s;
  976.     }
  977.  
  978. - (NSArray*)intArrayFromString:(NSString*)s
  979.     {
  980.     NSMutableArray* array = [NSMutableArray array];
  981.     NSScanner* scanner = [NSScanner scannerWithString:s];
  982.     int i;
  983.     while (![scanner isAtEnd])
  984.     if ([scanner scanInt:&i])
  985.         [array addObject:[NSNumber numberWithInt:i]];
  986.     return array;
  987.     }
  988.  
  989.  
  990. //-----------------------------------------------------------------------------
  991. // SLOT ORDER
  992. //-----------------------------------------------------------------------------
  993. - (NSArray*)slotOrder:(MiscBorderType)b
  994.     {
  995.     NSMutableArray* array = [NSMutableArray array];
  996.     MiscTableBorder const* const bp = info[b]->border;
  997.     MiscCoord_P const* const vmap = bp->getP2VMap();
  998.     int const lim = bp->count();
  999.     for (int i = 0;  i < lim;  i++)
  1000.     {
  1001.     int v = (vmap ? vmap[i] : i);
  1002.     if (bp->getSortDirection(v) == MISC_SORT_DESCENDING)
  1003.         v = ~v;
  1004.     [array addObject:[NSNumber numberWithInt:v]];
  1005.     }
  1006.     return array;
  1007.     }
  1008. - (NSArray*)columnOrder { return [self slotOrder:MISC_COL_BORDER]; }
  1009. - (NSArray*)rowOrder { return [self slotOrder:MISC_ROW_BORDER]; }
  1010.  
  1011. - (BOOL)border:(MiscBorderType)b setSlotOrder:(NSArray*)array
  1012.     {
  1013.     BOOL ret = NO;
  1014.     MiscTableBorder* const bp = info[b]->border;
  1015.     if (array != 0 && [array count] != 0)
  1016.     {
  1017.     unsigned int const lim = bp->count();
  1018.     if ([array count] == lim)
  1019.         {
  1020.         unsigned int const nbytes = lim * sizeof(int) + lim * sizeof(bool);
  1021.         int* const map = (int*) malloc( nbytes );
  1022.         NSParameterAssert( map != 0 );
  1023.         bool* const desc = (bool*) (map + lim);
  1024.  
  1025.         for (unsigned int i = 0; i < lim; i++)
  1026.         {
  1027.         int const j = [[array objectAtIndex:i] intValue];
  1028.         map[i] = (desc[i] = (j < 0)) ? ~j : j;
  1029.         }
  1030.  
  1031.         if (bp->setP2VMap( map ))
  1032.         {
  1033.         for (unsigned int i = 0; i < lim; i++)
  1034.             {
  1035.             MiscSortDirection const dir =
  1036.             (desc[i] ? MISC_SORT_DESCENDING : MISC_SORT_ASCENDING);
  1037.             if (dir != bp->getSortDirection( map[i] ))
  1038.             bp->setSortDirection( map[i], dir );
  1039.             }
  1040.  
  1041.             MiscBorderType const ob = otherBorder(b);
  1042.             if ([self autoSortSlots:ob])
  1043.             [self sortSlots:ob];
  1044.             ret = YES;
  1045.             }
  1046.  
  1047.         free( map );
  1048.         }
  1049.     }
  1050.     else
  1051.     {
  1052.     bp->setP2VMap(0);
  1053.     bp->clearSortDirection();
  1054.     ret = YES;
  1055.     }
  1056.  
  1057.     return ret;
  1058.     }
  1059.  
  1060. - (BOOL)setColumnOrder:(NSArray*)list
  1061.     { return [self border:MISC_COL_BORDER setSlotOrder:list]; }
  1062. - (BOOL)setRowOrder:(NSArray*)list
  1063.     { return [self border:MISC_ROW_BORDER setSlotOrder:list]; }
  1064.  
  1065. - (NSString*)slotOrderAsString:(MiscBorderType)b
  1066.     { return [self stringFromIntArray:[self slotOrder:b]]; }
  1067. - (NSString*)columnOrderAsString;
  1068.     { return [self slotOrderAsString:MISC_COL_BORDER]; }
  1069. - (NSString*)rowOrderAsString
  1070.     { return [self slotOrderAsString:MISC_ROW_BORDER]; }
  1071.  
  1072. - (BOOL)border:(MiscBorderType)b setSlotOrderFromString:(NSString*)s
  1073.     { return [self border:b setSlotOrder:[self intArrayFromString:s]]; }
  1074. - (BOOL)setColumnOrderFromString:(NSString*)s
  1075.     { return [self border:MISC_COL_BORDER setSlotOrderFromString:s]; }
  1076. - (BOOL)setRowOrderFromString:(NSString*)s
  1077.     { return [self border:MISC_ROW_BORDER setSlotOrderFromString:s]; }
  1078.  
  1079.  
  1080. //-----------------------------------------------------------------------------
  1081. // SLOT SIZES
  1082. //-----------------------------------------------------------------------------
  1083. - (NSArray*)slotSizes:(MiscBorderType)b
  1084.     {
  1085.     NSMutableArray* array = [NSMutableArray array];
  1086.     MiscTableBorder const* const bp = info[b]->border;
  1087.     int const lim = bp->count();
  1088.     for (int i = 0;  i < lim;  i++)
  1089.     [array addObject:[NSNumber numberWithInt:(int)bp->getSize_P(i)]];
  1090.     return array;
  1091.     }
  1092. - (NSArray*)columnSizes { return [self slotSizes:MISC_COL_BORDER]; }
  1093. - (NSArray*)rowSizes { return [self slotSizes:MISC_ROW_BORDER]; }
  1094.  
  1095. - (BOOL)border:(MiscBorderType)b setSlotSizes:(NSArray*)array
  1096.     {
  1097.     BOOL ret = NO;
  1098.     if (array != 0)
  1099.     {
  1100.     MiscTableBorder* const bp = info[b]->border;
  1101.     unsigned int const lim = bp->count();
  1102.     if ([array count] == lim)
  1103.         {
  1104.         for (unsigned int i = 0; i < lim; i++)
  1105.         {
  1106.         MiscPixels const min_size =
  1107.                 MiscPixels( [self border:b slotMinSize:i] );
  1108.         MiscPixels const max_size =
  1109.                 MiscPixels( [self border:b slotMaxSize:i] );
  1110.         MiscPixels s = MiscPixels([[array objectAtIndex:i] intValue]);
  1111.         if (s < min_size)
  1112.             s = min_size;
  1113.         else if (s > max_size)
  1114.             s = max_size;
  1115.         bp->setSize_P( i, s );
  1116.         }
  1117.         [self constrainSize];
  1118.         ret = YES;
  1119.         }
  1120.     }
  1121.     return ret;
  1122.     }
  1123. - (BOOL)setColumnSizes:(NSArray*)list
  1124.     { return [self border:MISC_COL_BORDER setSlotSizes:list]; }
  1125. - (BOOL)setRowSizes:(NSArray*)list
  1126.     { return [self border:MISC_ROW_BORDER setSlotSizes:list]; }
  1127.  
  1128. - (NSString*)slotSizesAsString:(MiscBorderType)b
  1129.     { return [self stringFromIntArray:[self slotSizes:b]]; }
  1130. - (NSString*)columnSizesAsString
  1131.     { return [self slotSizesAsString:MISC_COL_BORDER]; }
  1132. - (NSString*)rowSizesAsString
  1133.     { return [self slotSizesAsString:MISC_ROW_BORDER]; }
  1134.  
  1135. - (BOOL)border:(MiscBorderType)b setSlotSizesFromString:(NSString*)s
  1136.     { return [self border:b setSlotSizes:[self intArrayFromString:s]]; }
  1137. - (BOOL)setColumnSizesFromString:(NSString*)s
  1138.     { return [self border:MISC_COL_BORDER setSlotSizesFromString:s]; }
  1139. - (BOOL)setRowSizesFromString:(NSString*)s
  1140.     { return [self border:MISC_ROW_BORDER setSlotSizesFromString:s]; }
  1141.  
  1142.  
  1143.  
  1144. //-----------------------------------------------------------------------------
  1145. // Border Views
  1146. //-----------------------------------------------------------------------------
  1147. - (MiscCornerView*)cornerView        { return cornerView; }
  1148. - (NSString*)cornerTitle        { return [cornerView title]; }
  1149. - (void)setCornerTitle:(NSString*)s    { [cornerView setTitle:s]; }
  1150.  
  1151. - (BOOL)setBorder:(MiscBorderType)type on:(BOOL)on
  1152.     {
  1153.     MiscBorderInfo& b = *(info[type]);
  1154.     if (b.isOn != on)
  1155.     {
  1156.     BOOL const other_border_is_on = info[otherBorder(type)]->isOn;
  1157.     b.isOn = on;
  1158.     if (on)
  1159.         {
  1160.         if (other_border_is_on)
  1161.         [self addSubview:cornerView];
  1162.         [self addSubview:b.clip];
  1163.         NSRect r = [b.clip bounds];
  1164.         NSRect c = [[self contentView] bounds];
  1165.         if (type == MISC_COL_BORDER)
  1166.         {
  1167.         if (r.origin.x != c.origin.x)
  1168.             {
  1169.             r.origin.x = c.origin.x;
  1170.             [b.clip scrollToPoint:r.origin];
  1171.             }
  1172.         }
  1173.         else
  1174.         {
  1175.         if (r.origin.y != c.origin.y)
  1176.             {
  1177.             r.origin.y = c.origin.y;
  1178.             [b.clip scrollToPoint:r.origin];
  1179.             }
  1180.         }
  1181.         }
  1182.     else
  1183.         {
  1184.         [b.clip removeFromSuperview];
  1185.         if (other_border_is_on)
  1186.         [cornerView removeFromSuperview];
  1187.         }
  1188.     [self tile];
  1189.     [self constrainSize];
  1190.     [self setNeedsDisplay:YES];
  1191.     return YES;
  1192.     }
  1193.     return NO;
  1194.     }
  1195.  
  1196.  
  1197. //-----------------------------------------------------------------------------
  1198. // SLOT methods
  1199. //-----------------------------------------------------------------------------
  1200. - (MiscTableBorder*)border:(MiscBorderType)b
  1201.     { return info[b]->border; }
  1202. - (BOOL)border:(MiscBorderType)b setSlotTitlesOn:(BOOL)on_off
  1203.     { return [self setBorder:b on:on_off]; }
  1204. - (BOOL)slotTitlesOn:(MiscBorderType)b
  1205.     { return info[b]->isOn; }
  1206. - (MiscTableTitleMode)slotTitleMode:(MiscBorderType)b
  1207.     { return info[b]->border->getTitleMode(); }
  1208. - (void)border:(MiscBorderType)b setSlotTitleMode:(MiscTableTitleMode)x
  1209.     {
  1210.     MiscBorderInfo* const ip = info[b];
  1211.     if (ip->border->setTitleMode(x) && ip->isOn && ip->border->count() > 0)
  1212.         [ip->view setNeedsDisplay:YES];
  1213.     }
  1214.  
  1215. - (float)slotTitlesSize:(MiscBorderType)b
  1216.     { return info[b]->isOn ? [info[b]->view frameHeight] : 0; }
  1217. - (void)border:(MiscBorderType)b setSlotTitlesSize:(float)x
  1218.     {
  1219.     [info[b]->view setFrameHeight:(MiscPixels)floor(x)];
  1220.     [self tile];
  1221.     }
  1222.  
  1223. - (void)border:(MiscBorderType)b moveSlotFrom:(int)fromPos to:(int)toPos
  1224.     {
  1225.     info[b]->border->moveFromTo( fromPos, toPos );
  1226.     [self selectionChanged];
  1227.     }
  1228. - (int)border:(MiscBorderType)b slotPosition:(int)n
  1229.     { return info[b]->border->physicalToVisual(n); }
  1230. - (int)border:(MiscBorderType)b slotAtPosition:(int)n
  1231.     { return info[b]->border->visualToPhysical(n); }
  1232.  
  1233. - (NSArray*)border:(MiscBorderType)b physicalToVisual:(NSArray*)p_array
  1234.     {
  1235.     NSMutableArray* v_array = [NSMutableArray array];
  1236.     for (unsigned int i = 0, lim = [p_array count]; i < lim; i++)
  1237.         {
  1238.         MiscCoord_P const p = [[p_array objectAtIndex:i] intValue];
  1239.         MiscCoord_V const v = [self border:b slotPosition:p];
  1240.         [v_array addObject:[NSNumber numberWithInt:v]];
  1241.         }
  1242.     return v_array;
  1243.     }
  1244.  
  1245. - (NSArray*)border:(MiscBorderType)b visualToPhysical:(NSArray*)v_array
  1246.     {
  1247.     NSMutableArray* p_array = [NSMutableArray array];
  1248.     for (unsigned int i = 0, lim = [v_array count]; i < lim; i++)
  1249.         {
  1250.         MiscCoord_V const v = [[v_array objectAtIndex:i] intValue];
  1251.         MiscCoord_P const p = [self border:b slotAtPosition:v];
  1252.         [p_array addObject:[NSNumber numberWithInt:p]];
  1253.         }
  1254.     return p_array;
  1255.     }
  1256.  
  1257.  
  1258. - (BOOL)sizeableSlots:(MiscBorderType)b
  1259.     { return info[b]->border->isSizeable(); }
  1260. - (BOOL)draggableSlots:(MiscBorderType)b
  1261.     { return info[b]->border->isDraggable(); }
  1262. - (BOOL)modifierDragSlots:(MiscBorderType)b
  1263.     { return info[b]->border->isModifierDrag(); }
  1264. - (float)uniformSizeSlots:(MiscBorderType)b
  1265.     { return (float) info[b]->border->getUniformSize(); }
  1266. - (float)minUniformSizeSlots:(MiscBorderType)b
  1267.     { return (float) info[b]->border->getMinUniformSize(); }
  1268. - (float)maxUniformSizeSlots:(MiscBorderType)b
  1269.     { return (float) info[b]->border->getMaxUniformSize(); }
  1270.  
  1271. - (float)border:(MiscBorderType)b slotAdjustedSize:(int)n
  1272.     { return (float) info[b]->border->effectiveSize_P(n); }
  1273. - (float)border:(MiscBorderType)b slotSize:(int)n
  1274.     { return (float) info[b]->border->getSize_P(n); }
  1275. - (float)border:(MiscBorderType)b slotMinSize:(int)n
  1276.     { return (float) info[b]->border->getMinSize_P(n); }
  1277. - (float)border:(MiscBorderType)b slotMaxSize:(int)n
  1278.     { return (float) info[b]->border->getMaxSize_P(n); }
  1279. - (BOOL)border:(MiscBorderType)b slotIsSizeable:(int)n
  1280.     { return info[b]->border->isSizeable_P(n); }
  1281. - (BOOL)border:(MiscBorderType)b slotIsAutosize:(int)n
  1282.     { return info[b]->border->isSpringy_P(n); }
  1283. - (NSString*)border:(MiscBorderType)b slotTitle:(int)n
  1284.     { return info[b]->border->getTitle_P(n); }
  1285. - (int)border:(MiscBorderType)b slotTag:(int)n
  1286.     { return info[b]->border->getTag_P(n); }
  1287. - (MiscTableCellStyle)border:(MiscBorderType)b slotCellType:(int)n
  1288.     { return info[b]->border->getStyle_P(n); }
  1289. - (id)border:(MiscBorderType)b slotCellPrototype:(int)n
  1290.     { return info[b]->border->getPrototype_P(n); }
  1291.  
  1292. - (void)border:(MiscBorderType)b setSizeableSlots:(BOOL)flag
  1293.     { info[b]->border->setSizeable( flag ); }
  1294. - (void)border:(MiscBorderType)b setDraggableSlots:(BOOL)flag
  1295.     { info[b]->border->setDraggable( flag ); }
  1296. - (void)border:(MiscBorderType)b setModifierDragSlots:(BOOL)flag
  1297.     { info[b]->border->setModifierDrag( flag ); }
  1298. - (void)border:(MiscBorderType)b setUniformSizeSlots:(float)uniform_size
  1299.     {
  1300.     MiscBorderInfo* const ip = info[b];
  1301.     if (ip->border->setUniformSize((MiscPixels)floor(uniform_size)))
  1302.         {
  1303.         [self constrainSize];
  1304.         if (b == MISC_ROW_BORDER)
  1305.         {
  1306.         float const scr_size = uniform_size != 0 ?
  1307.             uniform_size : ip->border->getDefaultSize();
  1308.         [self setLineScroll:scr_size];
  1309.         [self setPageScroll:scr_size];
  1310.         }
  1311.         [self setNeedsDisplay:YES];
  1312.         }
  1313.     }
  1314.  
  1315. - (void)border:(MiscBorderType)b setMinUniformSizeSlots:(float)size
  1316.     { info[b]->border->setMinUniformSize( (MiscPixels)floor(size) ); }
  1317. - (void)border:(MiscBorderType)b setMaxUniformSizeSlots:(float)size
  1318.     { info[b]->border->setMaxUniformSize( (MiscPixels)floor(size) ); }
  1319.  
  1320. - (void)border:(MiscBorderType)b setSlot:(int)n size:(float)size
  1321.     {
  1322.     info[b]->border->setSize_P( n, (MiscPixels)floor(size) );
  1323.     [self constrainSize];
  1324.     }
  1325. - (void)border:(MiscBorderType)b setSlot:(int)n minSize:(float)size
  1326.     {
  1327.     info[b]->border->setMinSize_P( n, (MiscPixels)floor(size) );
  1328.     [self constrainSize];
  1329.     }
  1330. - (void)border:(MiscBorderType)b setSlot:(int)n maxSize:(float)size
  1331.     {
  1332.     info[b]->border->setMaxSize_P( n, (MiscPixels)floor(size) );
  1333.     [self constrainSize];
  1334.     }
  1335. - (void)border:(MiscBorderType)b setSlot:(int)n sizeable:(BOOL)flag
  1336.     { info[b]->border->setSizeable_P( n, flag ); }
  1337. - (void)border:(MiscBorderType)b setSlot:(int)n autosize:(BOOL)flag
  1338.     {
  1339.     info[b]->border->setSpringy_P( n, flag );
  1340.     [self constrainSize];
  1341.     }
  1342.  
  1343. - (void)border:(MiscBorderType)b setSlot:(int)n title:(NSString*)title
  1344.     {
  1345.     MiscBorderInfo* const ip = info[b];
  1346.     if (ip->border->setTitle_P( n, title ) && ip->isOn)
  1347.         [ip->view setNeedsDisplay:YES];
  1348.     }
  1349.  
  1350. - (void)border:(MiscBorderType)b setSlot:(int)n tag:(int)x
  1351.     { info[b]->border->setTag_P( n, x ); }
  1352. - (void)border:(MiscBorderType)b setSlot:(int)n
  1353.         cellType:(MiscTableCellStyle)type
  1354.     { info[b]->border->setStyle_P(n,type); }
  1355. - (void)border:(MiscBorderType)b setSlot:(int)n cellPrototype:(id)p
  1356.     { info[b]->border->setPrototype_P(n,p); }
  1357.  
  1358.  
  1359.  
  1360. //-----------------------------------------------------------------------------
  1361. // COLUMN methods
  1362. //-----------------------------------------------------------------------------
  1363. - (MiscTableBorder*)columnBorder
  1364.     { return colInfo.border; }
  1365. - (BOOL)columnTitlesOn
  1366.     { return [self slotTitlesOn:MISC_COL_BORDER]; }
  1367. - (BOOL)setColumnTitlesOn:(BOOL)x
  1368.     { return [self setBorder:MISC_COL_BORDER on:x]; }
  1369. - (MiscTableTitleMode)columnTitleMode
  1370.     { return [self slotTitleMode:MISC_COL_BORDER]; }
  1371. - (void)setColumnTitleMode:(MiscTableTitleMode)x
  1372.     { [self border:MISC_COL_BORDER setSlotTitleMode:x]; }
  1373. - (float)columnTitlesHeight
  1374.     { return [self slotTitlesSize:MISC_COL_BORDER]; }
  1375. - (void)setColumnTitlesHeight:(float)x
  1376.     { [self border:MISC_COL_BORDER setSlotTitlesSize:x]; }
  1377. - (MiscBorderView*)colTitles
  1378.     { return ([self columnTitlesOn] ? colInfo.view : 0); }
  1379.  
  1380. - (void)moveColumnFrom:(int)fromPos to:(int)toPos
  1381.     { [self border:MISC_COL_BORDER moveSlotFrom:fromPos to:toPos]; }
  1382. - (int)columnPosition:(int)n
  1383.     { return [self border:MISC_COL_BORDER slotPosition:n]; }
  1384. - (int)columnAtPosition:(int)n
  1385.     { return [self border:MISC_COL_BORDER slotAtPosition:n]; }
  1386.  
  1387. - (BOOL)sizeableColumns
  1388.     { return [self sizeableSlots:MISC_COL_BORDER]; }
  1389. - (BOOL)draggableColumns
  1390.     { return [self draggableSlots:MISC_COL_BORDER]; }
  1391. - (BOOL)modifierDragColumns
  1392.     { return [self modifierDragSlots:MISC_COL_BORDER]; }
  1393. - (float)uniformSizeColumns
  1394.     { return [self uniformSizeSlots:MISC_COL_BORDER]; }
  1395. - (float)minUniformSizeColumns
  1396.     { return [self minUniformSizeSlots:MISC_COL_BORDER]; }
  1397. - (float)maxUniformSizeColumns
  1398.     { return [self maxUniformSizeSlots:MISC_COL_BORDER]; }
  1399.  
  1400. - (float)columnAdjustedSize:(int)n
  1401.     { return [self border:MISC_COL_BORDER slotAdjustedSize:n]; }
  1402. - (float)columnSize:(int)n
  1403.     { return [self border:MISC_COL_BORDER slotSize:n]; }
  1404. - (float)columnMinSize:(int)n
  1405.     { return [self border:MISC_COL_BORDER slotMinSize:n]; }
  1406. - (float)columnMaxSize:(int)n
  1407.     { return [self border:MISC_COL_BORDER slotMaxSize:n]; }
  1408. - (BOOL)columnIsSizeable:(int)n
  1409.     { return [self border:MISC_COL_BORDER slotIsSizeable:n]; }
  1410. - (BOOL)columnIsAutosize:(int)n
  1411.     { return [self border:MISC_COL_BORDER slotIsAutosize:n]; }
  1412. - (NSString*)columnTitle:(int)n
  1413.     { return [self border:MISC_COL_BORDER slotTitle:n]; }
  1414. - (int)columnTag:(int)n
  1415.     { return [self border:MISC_COL_BORDER slotTag:n]; }
  1416. - (MiscTableCellStyle)columnCellType:(int)n
  1417.     { return [self border:MISC_COL_BORDER slotCellType:n]; }
  1418. - (id)columnCellPrototype:(int)n
  1419.     { return [self border:MISC_COL_BORDER slotCellPrototype:n]; }
  1420.  
  1421. - (void)setSizeableColumns:(BOOL)flag
  1422.     { [self border:MISC_COL_BORDER setSizeableSlots:flag]; }
  1423. - (void)setDraggableColumns:(BOOL)flag
  1424.     { [self border:MISC_COL_BORDER setDraggableSlots:flag]; }
  1425. - (void)setModifierDragColumns:(BOOL)flag
  1426.     { [self border:MISC_COL_BORDER setModifierDragSlots:flag]; }
  1427. - (void)setUniformSizeColumns:(float)size
  1428.     { [self border:MISC_COL_BORDER setUniformSizeSlots:size]; }
  1429. - (void)setMinUniformSizeColumns:(float)size
  1430.     { [self border:MISC_COL_BORDER setMinUniformSizeSlots:size]; }
  1431. - (void)setMaxUniformSizeColumns:(float)size
  1432.     { [self border:MISC_COL_BORDER setMaxUniformSizeSlots:size]; }
  1433.  
  1434. - (void)setColumn:(int)n size:(float)size
  1435.     { [self border:MISC_COL_BORDER setSlot:n size:size]; }
  1436. - (void)setColumn:(int)n minSize:(float)size
  1437.     { [self border:MISC_COL_BORDER setSlot:n minSize:size]; }
  1438. - (void)setColumn:(int)n maxSize:(float)size
  1439.     { [self border:MISC_COL_BORDER setSlot:n maxSize:size]; }
  1440. - (void)setColumn:(int)n sizeable:(BOOL)flag
  1441.     { [self border:MISC_COL_BORDER setSlot:n sizeable:flag]; }
  1442. - (void)setColumn:(int)n autosize:(BOOL)flag
  1443.     { [self border:MISC_COL_BORDER setSlot:n autosize:flag]; }
  1444. - (void)setColumn:(int)n title:(NSString*)title
  1445.     { [self border:MISC_COL_BORDER setSlot:n title:title]; }
  1446. - (void)setColumn:(int)n tag:(int)x
  1447.     { [self border:MISC_COL_BORDER setSlot:n tag:x]; }
  1448. - (void)setColumn:(int)n cellType:(MiscTableCellStyle)x
  1449.     { [self border:MISC_COL_BORDER setSlot:n cellType:x]; }
  1450. - (void)setColumn:(int)n cellPrototype:(id)p
  1451.     { [self border:MISC_COL_BORDER setSlot:n cellPrototype:p]; }
  1452.  
  1453.  
  1454. //-----------------------------------------------------------------------------
  1455. // ROW methods
  1456. //-----------------------------------------------------------------------------
  1457. - (MiscTableBorder*)rowBorder
  1458.     { return rowInfo.border; }
  1459. - (BOOL)rowTitlesOn
  1460.     { return [self slotTitlesOn:MISC_ROW_BORDER]; }
  1461. - (BOOL)setRowTitlesOn:(BOOL)x
  1462.     { return [self setBorder:MISC_ROW_BORDER on:x]; }
  1463. - (MiscTableTitleMode)rowTitleMode
  1464.     { return [self slotTitleMode:MISC_ROW_BORDER]; }
  1465. - (void)setRowTitleMode:(MiscTableTitleMode)x
  1466.     { [self border:MISC_ROW_BORDER setSlotTitleMode:x]; }
  1467. - (float)rowTitlesWidth
  1468.     { return [self slotTitlesSize:MISC_ROW_BORDER]; }
  1469. - (void)setRowTitlesWidth:(float)x
  1470.     { [self border:MISC_ROW_BORDER setSlotTitlesSize:x]; }
  1471. - (MiscBorderView*)rowTitles
  1472.     { return ([self rowTitlesOn] ? rowInfo.view : 0); }
  1473.  
  1474. - (void)moveRowFrom:(int)fromPos to:(int)toPos
  1475.     { [self border:MISC_ROW_BORDER moveSlotFrom:fromPos to:toPos]; }
  1476. - (int)rowPosition:(int)n
  1477.     { return [self border:MISC_ROW_BORDER slotPosition:n]; }
  1478. - (int)rowAtPosition:(int)n
  1479.     { return [self border:MISC_ROW_BORDER slotAtPosition:n]; }
  1480.  
  1481. - (BOOL)sizeableRows
  1482.     { return [self sizeableSlots:MISC_ROW_BORDER]; }
  1483. - (BOOL)draggableRows
  1484.     { return [self draggableSlots:MISC_ROW_BORDER]; }
  1485. - (BOOL)modifierDragRows
  1486.     { return [self modifierDragSlots:MISC_ROW_BORDER]; }
  1487. - (float)uniformSizeRows
  1488.     { return [self uniformSizeSlots:MISC_ROW_BORDER]; }
  1489. - (float)minUniformSizeRows
  1490.     { return [self minUniformSizeSlots:MISC_ROW_BORDER]; }
  1491. - (float)maxUniformSizeRows
  1492.     { return [self maxUniformSizeSlots:MISC_ROW_BORDER]; }
  1493.  
  1494. - (float)rowAdjustedSize:(int)n
  1495.     { return [self border:MISC_ROW_BORDER slotAdjustedSize:n]; }
  1496. - (float)rowSize:(int)n
  1497.     { return [self border:MISC_ROW_BORDER slotSize:n]; }
  1498. - (float)rowMinSize:(int)n
  1499.     { return [self border:MISC_ROW_BORDER slotMinSize:n]; }
  1500. - (float)rowMaxSize:(int)n
  1501.     { return [self border:MISC_ROW_BORDER slotMaxSize:n]; }
  1502. - (BOOL)rowIsSizeable:(int)n
  1503.     { return [self border:MISC_ROW_BORDER slotIsSizeable:n]; }
  1504. - (BOOL)rowIsAutosize:(int)n
  1505.     { return [self border:MISC_ROW_BORDER slotIsAutosize:n]; }
  1506. - (NSString*)rowTitle:(int)n
  1507.     { return [self border:MISC_ROW_BORDER slotTitle:n]; }
  1508. - (int)rowTag:(int)n
  1509.     { return [self border:MISC_ROW_BORDER slotTag:n]; }
  1510. - (MiscTableCellStyle)rowCellType:(int)n
  1511.     { return [self border:MISC_ROW_BORDER slotCellType:n]; }
  1512. - (id)rowCellPrototype:(int)n
  1513.     { return [self border:MISC_ROW_BORDER slotCellPrototype:n]; }
  1514.  
  1515. - (void)setSizeableRows:(BOOL)flag
  1516.     { [self border:MISC_ROW_BORDER setSizeableSlots:flag]; }
  1517. - (void)setDraggableRows:(BOOL)flag
  1518.     { [self border:MISC_ROW_BORDER setDraggableSlots:flag]; }
  1519. - (void)setModifierDragRows:(BOOL)flag
  1520.     { [self border:MISC_ROW_BORDER setModifierDragSlots:flag]; }
  1521. - (void)setUniformSizeRows:(float)size
  1522.     { [self border:MISC_ROW_BORDER setUniformSizeSlots:size]; }
  1523. - (void)setMinUniformSizeRows:(float)size
  1524.     { [self border:MISC_ROW_BORDER setMinUniformSizeSlots:size]; }
  1525. - (void)setMaxUniformSizeRows:(float)size
  1526.     { [self border:MISC_ROW_BORDER setMaxUniformSizeSlots:size]; }
  1527.  
  1528. - (void)setRow:(int)n size:(float)size
  1529.     { [self border:MISC_ROW_BORDER setSlot:n size:size]; }
  1530. - (void)setRow:(int)n minSize:(float)size
  1531.     { [self border:MISC_ROW_BORDER setSlot:n minSize:size]; }
  1532. - (void)setRow:(int)n maxSize:(float)size
  1533.     { [self border:MISC_ROW_BORDER setSlot:n maxSize:size]; }
  1534. - (void)setRow:(int)n sizeable:(BOOL)flag
  1535.     { [self border:MISC_ROW_BORDER setSlot:n sizeable:flag]; }
  1536. - (void)setRow:(int)n autosize:(BOOL)flag
  1537.     { [self border:MISC_ROW_BORDER setSlot:n autosize:flag]; }
  1538. - (void)setRow:(int)n title:(NSString*)title
  1539.     { [self border:MISC_ROW_BORDER setSlot:n title:title]; }
  1540. - (void)setRow:(int)n tag:(int)x
  1541.     { [self border:MISC_ROW_BORDER setSlot:n tag:x]; }
  1542. - (void)setRow:(int)n cellType:(MiscTableCellStyle)x
  1543.     { [self border:MISC_ROW_BORDER setSlot:n cellType:x]; }
  1544. - (void)setRow:(int)n cellPrototype:(id)p
  1545.     { [self border:MISC_ROW_BORDER setSlot:n cellPrototype:p]; }
  1546.  
  1547.  
  1548. //-----------------------------------------------------------------------------
  1549. // DRAWING
  1550. //    FIXME: This should all be routed through the -display::: mechanism
  1551. //    so that the lockFocus can be done automatically, and so that
  1552. //    subviews will have an opportunity to draw themselves.
  1553. //-----------------------------------------------------------------------------
  1554.  
  1555. - (void)drawCellAtRow:(int)row column:(int)col
  1556.     {
  1557.     if ([tableView canDraw])
  1558.     {
  1559.     [tableView lockFocus];
  1560.     [tableView drawCellAtRow:row column:col];
  1561.     [tableView unlockFocus];
  1562.     [[self window] flushWindow];
  1563.     }
  1564.     }
  1565.  
  1566. - (void)drawRow:(int)row
  1567.     {
  1568.     if ([tableView canDraw])
  1569.     {
  1570.     [tableView lockFocus];
  1571.     [tableView drawRow:row];
  1572.     [tableView unlockFocus];
  1573.     [[self window] flushWindow];
  1574.     }
  1575.     }
  1576.  
  1577. - (void)drawColumn:(int)col
  1578.     {
  1579.     if ([tableView canDraw])
  1580.     {
  1581.     [tableView lockFocus];
  1582.     [tableView drawColumn:col];
  1583.     [tableView unlockFocus];
  1584.     [[self window] flushWindow];
  1585.     }
  1586.     }
  1587.  
  1588. - (void)border:(MiscBorderType)b drawSlot:(int)n
  1589.     { if (b == MISC_COL_BORDER) [self drawColumn:n]; else [self drawRow:n]; }
  1590.  
  1591. - (void)border:(MiscBorderType)b drawSlotTitle:(int)n    // physical position.
  1592.     {
  1593.     MiscBorderInfo* const ip = info[b];
  1594.     if (ip->isOn)                    // visual position.
  1595.     {
  1596.     MiscBorderView* const v = ip->view;
  1597.     if ([v canDraw])
  1598.         {
  1599.         [v lockFocus];
  1600.         [v drawSlot:[self border:b slotPosition:n]];
  1601.         [v unlockFocus];
  1602.         [[self window] flushWindow];
  1603.         }
  1604.     }
  1605.     }
  1606. - (void)drawRowTitle:(int)n
  1607.     { [self border:MISC_ROW_BORDER drawSlotTitle:n]; }
  1608. - (void)drawColumnTitle:(int)n
  1609.     { [self border:MISC_COL_BORDER drawSlotTitle:n]; }
  1610.  
  1611. - (BOOL)drawClippedText            { return drawClippedText; }
  1612. - (void)setDrawClippedText:(BOOL)x
  1613.     {
  1614.     if (drawClippedText != x)
  1615.     {
  1616.     drawClippedText = x;
  1617.     [self setNeedsDisplay:YES];
  1618.     }
  1619.     }
  1620.  
  1621. //-----------------------------------------------------------------------------
  1622. // VISIBLE / SCROLLING
  1623. //-----------------------------------------------------------------------------
  1624.  
  1625. - (void)scrollCellToVisibleAtRow:(int)row column:(int)col
  1626.     { [tableView scrollCellToVisibleAtRow:row column:col]; }
  1627. - (void)scrollRowToVisible:(int)row { [tableView scrollRowToVisible:row]; }
  1628. - (void)scrollColumnToVisible:(int)col
  1629.     { [tableView scrollColumnToVisible:col]; }
  1630. - (void)scrollSelectionToVisible
  1631.     {
  1632.     if ([self hasRowSelection])
  1633.     [self scrollRowToVisible:[self selectedRow]];
  1634.     else if ([self hasColumnSelection])
  1635.     [self scrollColumnToVisible:[self selectedColumn]];
  1636.     }
  1637.  
  1638.  
  1639. - (int)numberOfVisibleSlots:(MiscBorderType)b
  1640.     { return [tableView numberOfVisibleSlots:b]; }
  1641. - (int)firstVisibleSlot:(MiscBorderType)b
  1642.     { return [tableView firstVisibleSlot:b]; }
  1643. - (int)lastVisibleSlot:(MiscBorderType)b
  1644.     { return [tableView lastVisibleSlot:b]; }
  1645. - (BOOL)border:(MiscBorderType)b slotIsVisible:(int)n
  1646.     { return [tableView border:b slotIsVisible:n]; }
  1647. - (void)border:(MiscBorderType)b setFirstVisibleSlot:(int)n
  1648.     { [tableView border:b setFirstVisibleSlot:n]; }
  1649. - (void)border:(MiscBorderType)b setLastVisibleSlot:(int)n
  1650.     { [tableView border:b setLastVisibleSlot:n]; }
  1651.  
  1652. - (int)numberOfVisibleColumns
  1653.     { return [self numberOfVisibleSlots:MISC_COL_BORDER]; }
  1654. - (int)firstVisibleColumn
  1655.     { return [self firstVisibleSlot:MISC_COL_BORDER]; }
  1656. - (int)lastVisibleColumn
  1657.     { return [self lastVisibleSlot:MISC_COL_BORDER]; }
  1658. - (BOOL)columnIsVisible:(int)n
  1659.     { return [self border:MISC_COL_BORDER slotIsVisible:n]; }
  1660. - (void)setFirstVisibleColumn:(int)n
  1661.     { [self border:MISC_COL_BORDER setFirstVisibleSlot:n]; }
  1662. - (void)setLastVisibleColumn:(int)n
  1663.     { [self border:MISC_COL_BORDER setLastVisibleSlot:n]; }
  1664.  
  1665. - (int)numberOfVisibleRows
  1666.     { return [self numberOfVisibleSlots:MISC_ROW_BORDER]; }
  1667. - (int)firstVisibleRow
  1668.     { return [self firstVisibleSlot:MISC_ROW_BORDER]; }
  1669. - (int)lastVisibleRow
  1670.     { return [self lastVisibleSlot:MISC_ROW_BORDER]; }
  1671. - (BOOL)rowIsVisible:(int)n
  1672.     { return [self border:MISC_ROW_BORDER slotIsVisible:n]; }
  1673. - (void)setFirstVisibleRow:(int)n
  1674.     { [self border:MISC_ROW_BORDER setFirstVisibleSlot:n]; }
  1675. - (void)setLastVisibleRow:(int)n
  1676.     { [self border:MISC_ROW_BORDER setLastVisibleSlot:n]; }
  1677.  
  1678.  
  1679. //-----------------------------------------------------------------------------
  1680. // *FIXME*
  1681. //    OPENSTEP 4.2 Objective-C++ compiler for NT (final release) crashes
  1682. //    whenever a message is sent to 'super' from within a category.  This
  1683. //    bug also afflicts the 4.2 (prerelease) compiler for Mach and NT.
  1684. //    Work around it by providing stub methods in the main (non-category)
  1685. //    implementation which merely forward the appropriate message to 'super'
  1686. //    on behalf of the categories.  Though ugly, it works, is very
  1687. //    localized, and simple to remove when the bug is finally fixed.
  1688. //-----------------------------------------------------------------------------
  1689. - (id)superInitWithCoder:(NSCoder*)coder
  1690.         { return [super initWithCoder:coder]; }
  1691. - (void)superEncodeWithCoder:(NSCoder*)coder
  1692.     { [super encodeWithCoder:coder]; }
  1693. - (void)superKeyDown:(NSEvent*)p
  1694.     { [super keyDown:p]; }
  1695. - (id)superValidRequestorForSendType:(NSString*)s returnType:(NSString*)r
  1696.     { return [super validRequestorForSendType:s returnType:r]; }
  1697.  
  1698. @end
  1699.