home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Think Class Libraries / CScrollList 1.0 / CScrollList Classes / CScrollList.c next >
Encoding:
C/C++ Source or Header  |  1994-11-30  |  39.2 KB  |  1,582 lines  |  [TEXT/KAHL]

  1. /*************************************************************************************
  2.  
  3.  CScrollList.c
  4.     
  5.         A scrolling list that displays information in a CArray.  Combines all the
  6.         good qualities of CTable and CArrayPane but keeps it to one column with
  7.         one uniform rowheight and only one selected cell.  Provides four options:
  8.         
  9.         SELECTABLE
  10.         
  11.         If this option is not selected, the currently selected cell will not be
  12.         hilited (except when dragging).  This is useful when combined with the
  13.         checkable option to create a check list that can't be edited or rearranged.
  14.         
  15.         CHECKABLE
  16.         
  17.         Maintains a separate CStateArray to track the state (checked or not checked)
  18.         of each item in the CArray.  Keeps both arrays in sync with each other.
  19.         
  20.         DRAGABLE
  21.         
  22.         Allows array elements to be arranged in any order by dragging them.
  23.         
  24.         EDITABLE
  25.         
  26.         Implements the editing of the CArray elements.  This is an abstract class
  27.         that holds the framework for editing cells, but makes no assumptions as to
  28.         the contents of those cells.  Several methods that access the data in the
  29.         linked array must be overriden in order to allow the array to actually be
  30.         changed.  Subclasses should install subpanes during editing.
  31.         
  32.             OVERRIDE these methods to use
  33.             {
  34.                 DoInsertCell( void)
  35.                 BeginEditing( void)
  36.                 SetupCellData( void)
  37.                 RetrieveCellData( void)
  38.                 DoneEditing( void)
  39.             }
  40.         
  41.         While editing, selectedCell is the cell being edited.
  42.         
  43.         THINGS TO CHANGE/ADD
  44.         
  45.     x    Fix Panorama Coordinates & Scrolling
  46.             Still can't have the panorama origin be at (1,1), but at least
  47.             it's one cell to one vertical panorama unit, finally!
  48.     x    Fix SELECTABLE option.
  49.             Not totally complete.  Really, there should never be a selected
  50.             cell at all, except maybe when dragging, and even then...
  51.     x    Add FrameCell for dragging.
  52.             It only does the same thing as hiliting, but it needed to bypass
  53.             the standard call.  Even when SELECTABLE is off, we still want
  54.             the cell being dragged to show itself first.
  55.     x    Create a DrawCell and DrawCellRange CChore for updates.
  56.             This has since been removed due to a problem in which the scroll
  57.             list is disposed out from underneath the chore.  The motivation
  58.             behind creating the chore has also been fixed.  6/8/92
  59.         Automatic offscreen drawing.
  60.             Dream on...
  61.     
  62.     SUPERCLASS = CPanorama
  63.     
  64.     REQUIREMENTS: CScrollListDragger
  65.                   CTextEnvirons
  66.                   CStateArray
  67.                   gCheckCursor - expected to be loaded and locked in memory
  68.     
  69.         © 1992 Dave Harkness
  70.  
  71. *************************************************************************************/
  72.  
  73.  
  74. #include "CScrollList.h"
  75. #include "CScrollListDragger.h"
  76. #include "CStateArray.h"
  77.  
  78. #include <CArray.h>
  79. #include <CTextEnvirons.h>
  80. #include <CScrollPane.h>
  81. #include <CPaneBorder.h>
  82. #include <CList.h>
  83. #include <CApplication.h>
  84. #include <Constants.h>
  85. #include <Commands.h>
  86. #include <Global.h>
  87.  
  88.  
  89. #define kDefaultHIndent        3    // room for edges
  90. #define kCheckWidth            9    // room for the check mark
  91.  
  92. #define kBorderMargin        1    // margin of active border
  93. #define kBorderPen            2    // pen size of active border
  94.  
  95. #define kReturnKey        0x0D
  96. #define kDeleteKey        0x08
  97.  
  98.  
  99.         // Macros for testing the various list options
  100.  
  101. #define SELECTABLE        (listOptions & kSLSelectable)
  102. #define DRAGABLE        (listOptions & kSLDragable)
  103. #define CHECKABLE        (listOptions & kSLCheckable)
  104. #define EDITABLE        (listOptions & kSLEditable)
  105.  
  106.  
  107. extern CBureaucrat        *gGopher;
  108. extern short            gClicks;
  109. extern CursHandle        gCheckCursor;
  110.  
  111.  
  112. /*************************************************************************************
  113.  IScrollList
  114. *************************************************************************************/
  115.  
  116. void
  117. CScrollList::IScrollList( CView *anEnclosure, CBureaucrat *aSupervisor,
  118.                           short aWidth, short aHeight,
  119.                           short aHEncl, short aVEncl,
  120.                           SizingOption aHSizing, SizingOption aVSizing,
  121.                           short fOptions)
  122.  
  123. {
  124.     CPanorama::IPanorama( anEnclosure, aSupervisor, aWidth, aHeight,
  125.                           aHEncl, aVEncl, aHSizing, aVSizing);
  126.             
  127.     SetWantsClicks( TRUE);                                // we want to be clicked!
  128.     
  129.     IScrollListX( fOptions);
  130.  
  131. }  /* CScrollList::IScrollList */
  132.  
  133.  
  134. /*************************************************************************************
  135.  IViewTemp  {OVERRRIDE}
  136.  
  137.     Extract the extra information from a 'SLst' resource.
  138. *************************************************************************************/
  139.  
  140. void
  141. CScrollList::IViewTemp( CView *anEnclosure, CBureaucrat *aSupervisor,
  142.                         Ptr viewData)
  143. {
  144.     tScrollListTempP    template = (tScrollListTempP) viewData;
  145.     
  146.     inherited::IViewTemp( anEnclosure, aSupervisor, viewData);
  147.     IScrollListX( template->listOptions);
  148.     
  149.     SetDblClickCmd( template->dblClickCmd);
  150.     SetDrawActiveBorder( template->drawActiveBorder != 0);
  151.     
  152.  
  153. }  /* CScrollList::IViewTemp */
  154.  
  155.  
  156. /*************************************************************************************
  157.  IScrollListX
  158.  
  159.     Perform basic initialization that will be used for every creation method.
  160. *************************************************************************************/
  161.  
  162. void
  163. CScrollList::IScrollListX( short fOptions)
  164.  
  165. {
  166.     FontInfo        fInfo;
  167.     
  168.             // Lists will be limited to 32767 pixels (approx. 20000 lines of text).
  169.             // If that isn't enough, change usingLongCoord to TRUE.  CScrollList,
  170.             // and its subclasses, will use FrameToQD for converting to/from
  171.             // frame coordinates, instead of LongToQD.  This means that no additional
  172.             // changes must be made.
  173.     
  174.     usingLongCoord = FALSE;
  175.     
  176.     numCells = 0;                        // no cells and no selection
  177.     selectedCell = 0;
  178.     itsArray = NULL;
  179.     itsChecks = NULL;
  180.     
  181.     SetCanBeGopher( FALSE);                // no array yet, so can't be gopher ====
  182.     drawActiveBorder = TRUE;
  183.     dblClickCmd = cmdNull;
  184.     listOptions = fOptions;
  185.     
  186.     fEditing = FALSE;
  187.     fStillEditing = FALSE;
  188.     
  189.     CreateTextEnvironment();            // setup the desired text characteristics
  190.     Prepare();                            // setup the port and restore the text
  191.                                         // environment
  192.     
  193.     GetFontInfo( &fInfo);
  194.     fontInfo = fInfo;                    // set the instance variable
  195.     cellHeight = fInfo.ascent + fInfo.descent + fInfo.leading;
  196.     
  197.             // add a pixel extra on the top and bottom of cells to look nice
  198.     cellHeight += 2;
  199.     
  200.     SetScales( width, cellHeight);
  201.     SetPt( &indent, kDefaultHIndent + (kCheckWidth * (CHECKABLE != 0)),
  202.                     fInfo.ascent + 1);
  203.  
  204. }  /* CScrollList::IScrollListX */
  205.  
  206.  
  207. /*************************************************************************************
  208.  CreateTextEnvironment
  209.     
  210.     Create and initialize the text environment used for drawing text.
  211.     it will also be used for calculating the default indent and cell height.
  212. *************************************************************************************/
  213.  
  214. void
  215. CScrollList::CreateTextEnvironment( void)
  216.  
  217. {
  218.     CTextEnvirons    *textEnvirons;
  219.     TextInfoRec        textInfo;
  220.     
  221.     textEnvirons = new( CTextEnvirons);
  222.     itsEnvironment = textEnvirons;
  223.     textEnvirons->ITextEnvirons();
  224.     
  225.     textInfo.fontNumber = geneva;
  226.     textInfo.theSize = 9;
  227.     textInfo.theStyle = 0;
  228.     textInfo.theMode = srcOr;
  229.     
  230.     textEnvirons->SetTextInfo( &textInfo);
  231.  
  232. }  /* CScrollList::CreateTextEnvironment */
  233.  
  234.  
  235. /*************************************************************************************
  236.  SetScrollPane  {OVERRIDE}
  237.  
  238.     Make sure the steps and overlap for our ScrollPane are set up correctly.
  239. *************************************************************************************/
  240.  
  241. void
  242. CScrollList::SetScrollPane( CScrollPane *aScrollPane)
  243.  
  244. {
  245.     inherited::SetScrollPane( aScrollPane);
  246.     
  247.     itsScrollPane->SetSteps( 1, 1);
  248.     itsScrollPane->SetOverlaps( 0, 1);
  249.  
  250. }  /* CScrollList::SetScrollPane */
  251.  
  252.  
  253. /*************************************************************************************
  254.  AdjustCursor  {OVERRIDE}
  255.  
  256.     Adjust the cursor to be either the check mark or the arrow apporpriately.
  257. *************************************************************************************/
  258.  
  259. void
  260. CScrollList::AdjustCursor( Point where, RgnHandle mouseRgn)
  261.  
  262. {
  263.     LongPt        locWhere;
  264.     RgnHandle    myRgn;
  265.     Rect        globalRect;
  266.     LongRect    frameRect;
  267.     
  268.     WindToFrame( where, &locWhere);
  269.     
  270.     if ( CHECKABLE && locWhere.h < indent.h )
  271.     {
  272.         SetCursor( *gCheckCursor);                        // Set to check cursor
  273.         GetAperture( &frameRect);
  274.         frameRect.right = frameRect.left + indent.h;
  275.     }
  276.     else
  277.     {
  278.         SetCursor( &arrow);                                // Set to arrow cursor
  279.         GetAperture( &frameRect);
  280.         frameRect.left += indent.h;
  281.     }
  282.     
  283.     myRgn = NewRgn();
  284.     if ( myRgn != NULL )
  285.     {
  286.         FrameToGlobalR( &frameRect, &globalRect);        // Convert to global coords
  287.         RectRgn( myRgn, &globalRect);
  288.         SectRgn( mouseRgn, myRgn, mouseRgn);            // and clip to old mouseRgn
  289.         DisposeRgn( myRgn);
  290.     }
  291.  
  292. }  /* CScrollList::AdjustCursor */
  293.  
  294.  
  295. /*************************************************************************************
  296.  MakeMouseTask
  297.  
  298.     Create a cell dragging mousetask.
  299.     
  300.     RETURNS the MouseTask
  301. *************************************************************************************/
  302.  
  303. CMouseTask *
  304. CScrollList::MakeMouseTask( short modifiers)
  305.  
  306. {
  307.     CScrollListDragger    *theTask;
  308.     
  309.     theTask = new( CScrollListDragger);
  310.     theTask->IScrollListDragger( this, modifiers, cellHeight, listOptions);
  311.     
  312.     return theTask;
  313.  
  314. }  /* CScrollList::MakeMouseTask */
  315.  
  316.  
  317. /*************************************************************************************
  318.  DoClick  {OVERRIDE}
  319.  
  320.     Handle clicks and drags.  A single click just selects the cell for editing.
  321.     If the list is a check list, it might check/uncheck the cell.
  322.     A double click sends the dblClickCmd.  A drag selects the cell and begins
  323.     tracking the mouse to move the cell within the list.
  324. *************************************************************************************/
  325.  
  326. void
  327. CScrollList::DoClick( Point hitPt, short modifierKeys, long when)
  328.  
  329. {
  330.     CMouseTask        *mouseTask;
  331.     LongRect        pinRect;
  332.     short            hitCell;
  333.     LongPt            pt;
  334.     long            hExtent, vExtent;
  335.         
  336.     QDToFrame( hitPt, &pt);
  337.     
  338.     if ( hitCell = FindHitCell( &pt) )
  339.     {
  340.         if ( gClicks == 2 )                                    // a double click?
  341.         {
  342.             DoDblClick( hitCell, modifierKeys, when);
  343.         }
  344.         else if ( CHECKABLE && (pt.h < indent.h) )            // check the cell
  345.         {
  346.             CheckCell( hitCell);
  347.         }
  348.         else if ( DRAGABLE )                                // drag the cell
  349.         {
  350.             mouseTask = MakeMouseTask( modifierKeys);
  351.             if ( mouseTask )
  352.             {
  353.                 GetPixelExtent( &hExtent, &vExtent);
  354.                 SetLongRect( &pinRect, 1, 1, hExtent - 1, vExtent - 1);
  355.                 TrackMouse( mouseTask, &pt, &pinRect);
  356.             }
  357.         }
  358.         else if ( SELECTABLE )                                // select the cell
  359.         {
  360.             SelectCell( hitCell, kDoRedraw);
  361.         }
  362.     }
  363.     else
  364.         ClickOutsideBounds( hitPt, modifierKeys, when);
  365.  
  366. }  /* CScrollList::DoClick */
  367.  
  368.  
  369. /*************************************************************************************
  370.  SetDblClickCmd
  371.  
  372.     Set the command sent to this object when a cell is double-clicked..
  373. *************************************************************************************/
  374.  
  375. void
  376. CScrollList::SetDblClickCmd( long aCmd)
  377.  
  378. {
  379.     dblClickCmd = aCmd;
  380.  
  381. }  /* CScrollList::SetDblClickCmd */
  382.  
  383.  
  384. /*************************************************************************************
  385.  DoDblClick
  386.  
  387.     If there is a double-click command, pass it along to this object so that
  388.     subclasses may handle it if they wish.  Default is to send it up the
  389.     chain of command..
  390. *************************************************************************************/
  391.  
  392. void
  393. CScrollList::DoDblClick( short hitCell, short modifierKeys, long when)
  394. {
  395.     if ( dblClickCmd != cmdNull )
  396.         DoCommand( dblClickCmd);
  397.  
  398. }  /* CScrollList::DoDblClick */
  399.  
  400.  
  401. /*************************************************************************************
  402.  HitSamePart  {OVERRIDE}
  403.  
  404.     The TCL calls HitSamePart to determine if two clicks are in the "same part" and
  405.     can be considered a double-click.
  406.     
  407.     RETURNS true if the clicks hit the same part.
  408. *************************************************************************************/
  409.  
  410. Boolean
  411. CScrollList::HitSamePart( Point pointA, Point pointB)
  412. {
  413.     short        cellA, cellB;
  414.     LongPt        ptA, ptB;
  415.     
  416.             // points are in window coords, convert to local coords
  417.     
  418.     WindToFrame( pointA, &ptA);
  419.     WindToFrame( pointB, &ptB);
  420.     
  421.             // find the cell hit by each point
  422.     
  423.     cellA = FindHitCell( &ptA);
  424.     cellB = FindHitCell( &ptB);
  425.     
  426.             // before we test the cells for equality, we must make sure that
  427.             // both points were in the table in the first place
  428.     
  429.     if ( (cellA > numCells || cellA < 1) || (cellB > numCells || cellB < 1) )
  430.         return FALSE;
  431.     else
  432.         return (cellA == cellB);
  433.  
  434. }  /* CScrollList::HitSamePart */
  435.  
  436.  
  437. /*************************************************************************************
  438.  AddCell
  439.  
  440.     Add a block of cells to the list at the given position.  Shifts all cells below
  441.     afterCell down howMany cells.  Forces a refresh of all affected cells.
  442.     Use 0 for afterCell to insert the new cells at the top of the list.
  443. *************************************************************************************/
  444.  
  445. void
  446. CScrollList::AddCell( short howMany, short afterCell)
  447. {
  448.     if ( howMany > 0 )
  449.     {
  450.                 // clip afterCell to actual cell count
  451.         
  452.         afterCell = Min( afterCell, numCells);
  453.         afterCell = Max( afterCell, 0);
  454.         
  455.         numCells += howMany;
  456.         
  457.         AdjustBounds();    
  458.         RefreshCellRange( afterCell+1, numCells);        // Redraw affected cells
  459.     }
  460.  
  461. }  /* CScrollList::AddCell */
  462.  
  463.  
  464. /*************************************************************************************
  465.  DeleteCell
  466.  
  467.     Delete a block of howMany cells starting at startCell.  Shifts all cells below
  468.     startCell up howMany cells.  Forces a refresh of all affected cells.
  469. *************************************************************************************/
  470.  
  471. void
  472. CScrollList::DeleteCell( short howMany, short startCell)
  473. {
  474.     short    newCell = selectedCell;
  475.     short    oldNumCells = numCells;
  476.     
  477.     if ( howMany > 0 && numCells > 0 )
  478.     {
  479.                 // Clip startCell and howMany to actual number of cells
  480.         
  481.         startCell = Min( numCells, startCell);
  482.         startCell = Max( startCell, 1);
  483.         howMany = Min( howMany, numCells - startCell + 1);
  484.         
  485.                 // If selectedCell is below the block of deleted cells,
  486.                 // shift it down howMany cells.
  487.         
  488.         if ( newCell >= startCell + howMany )
  489.             newCell -= howMany;
  490.         
  491.         numCells -= howMany;                            // adjust the list
  492.         newCell = Min( numCells, newCell);                // clip to cell range
  493.         AdjustBounds();
  494.         ScrollToSelection();
  495.         RefreshCellRange( startCell, oldNumCells);
  496.         SelectCell( newCell, kDontRedraw);
  497.     }
  498.  
  499. }  /* CScrollList::DeleteCell */
  500.  
  501.  
  502. /*************************************************************************************
  503.  AdjustBounds
  504.  
  505.     Adjusts the bounds instance variable in response to a change in the number
  506.     of cells in the list.
  507. *************************************************************************************/
  508.  
  509. void
  510. CScrollList::AdjustBounds( void)
  511.  
  512. {
  513.     LongRect    boundsR;
  514.     
  515.     SetLongRect( &boundsR, 0, 0, width, numCells);
  516.     SetBounds( &boundsR);
  517.  
  518. }  /* CScrollList::AdjustBounds */
  519.  
  520.  
  521. /*************************************************************************************
  522.  IsChecked
  523.  
  524.     Return TRUE if theCell is checked.
  525. *************************************************************************************/
  526.  
  527. Boolean
  528. CScrollList::IsChecked( short theCell)
  529.  
  530. {
  531.     ASSERT( CHECKABLE);
  532.     
  533.     return (itsChecks->GetState( theCell) != 0);
  534.  
  535. }  /* CScrollList::IsChecked */
  536.  
  537.  
  538. /*************************************************************************************
  539.  CheckCell
  540.  
  541.     Toggle the checked state of theCell.
  542. *************************************************************************************/
  543.  
  544. void
  545. CScrollList::CheckCell( short theCell)
  546.  
  547. {
  548.     ASSERT( CHECKABLE);
  549.     
  550.     itsChecks->ToggleState( theCell);
  551.     RefreshCell( theCell);
  552.  
  553. }  /* CScrollList::CheckCell */
  554.  
  555.  
  556. /*************************************************************************************
  557.  CheckAllCells
  558.  
  559.     Set the check state for all cells to fCheckState.
  560. *************************************************************************************/
  561.  
  562. void
  563. CScrollList::CheckAllCells( Boolean fCheckState)
  564.  
  565. {
  566.     ASSERT( CHECKABLE);
  567.     
  568.     itsChecks->SetAllStates( fCheckState);
  569.     Refresh();
  570.  
  571. }  /* CScrollList::CheckAllCells */
  572.  
  573.  
  574. /*************************************************************************************
  575.  GetCheckArray
  576.  
  577.     Return a copy of the itsChecks array.
  578. *************************************************************************************/
  579.  
  580. CStateArray *
  581. CScrollList::GetCheckArray( void)
  582.  
  583. {
  584.     ASSERT( CHECKABLE);
  585.     
  586.     return (CStateArray *)itsChecks->Copy();
  587.  
  588. }  /* CScrollList::GetCheckArray */
  589.  
  590.  
  591. /*************************************************************************************
  592.  Draw  {OVERRIDE}
  593.  
  594.     Draw the range of cells that intersect the given update area.
  595. *************************************************************************************/
  596.  
  597. void
  598. CScrollList::Draw( Rect *area)
  599. {
  600.     short        firstCell, lastCell, currCell;
  601.     LongRect     r, cellRect;
  602.     Rect        qdRect;
  603.     
  604.     QDToFrameR( area, &r);
  605.     
  606.     SetLongRect( &cellRect, 0, 0, width, numCells * cellHeight);
  607.     if ( !SectLongRect( &r, &cellRect, &r) )
  608.         return;
  609.     
  610.     r.right--;                        // Don't include cells not intended to be drawn
  611.     r.bottom--;
  612.     
  613.     firstCell = FindHitCell( &topLeftL(r));                // get cell range to draw
  614.     lastCell = FindHitCell( &botRightL(r));
  615.     
  616.     SetLongRect( &cellRect, 0, cellHeight * (firstCell - 1),
  617.                  width, cellHeight * firstCell);
  618.     
  619.     for ( currCell = firstCell; currCell <= lastCell; currCell++ )
  620.     {
  621.         FrameToQDR( &cellRect, &qdRect);                // convert to screen rect
  622.         DrawCell( currCell, &qdRect);
  623.         OffsetLongRect( &cellRect, 0, cellHeight);        // move to next cell
  624.     }
  625.     
  626.     if ( IsActive() && selectedCell >= firstCell && selectedCell <= lastCell )
  627.         Hilite( selectedCell, TRUE);
  628.  
  629. }  /* CScrollList::Draw */
  630.  
  631.  
  632. /*************************************************************************************
  633.  DrawCell
  634.  
  635.     Draw theCell into the given cellRect.  Default only draws the check, if any.
  636.     
  637.         OVERRIDE this method.
  638. *************************************************************************************/
  639.  
  640. void
  641. CScrollList::DrawCell( short theCell, Rect *cellRect)
  642.  
  643. {
  644.     if ( CHECKABLE && IsChecked( theCell) )                    // Draw the check mark
  645.     {
  646.         MoveTo( cellRect->left + indent.h - kCheckWidth,
  647.                 cellRect->top + indent.v - 2);
  648.         Line( 1, 1);
  649.         Line( 4, -4);
  650.     }
  651.  
  652. }  /* CScrollList::DrawCell */
  653.  
  654.  
  655. /*************************************************************************************
  656.  FrameCell
  657.  
  658.     Frame/unframe the specified cell in response to being dragged/released.
  659.     Assumes the Pane is already Prepared.  Default just performs the same
  660.     action as Hilite below.
  661. *************************************************************************************/
  662.  
  663. void
  664. CScrollList::FrameCell( short theCell, Boolean frameFlag)
  665.  
  666. {
  667.     LongRect    pixels;
  668.     Rect        visPixels;
  669.     
  670.     if ( !printing )
  671.     {
  672.         CellsToPixels( theCell, theCell, &pixels);
  673.         if ( SectAperture( &pixels, &visPixels) )
  674.         {
  675.             SetHiliteMode();                    // invert with user's hilite color
  676.             InvertRect( &visPixels);
  677.         }
  678.     }
  679.  
  680. }  /* CScrollList::FrameCell */
  681.  
  682.  
  683. /*************************************************************************************
  684.  Hilite
  685.  
  686.     Hilite the specified cell.  Assumes the Pane is already Prepared.
  687.     Does not hilite a cell being edited.  Only hilites if SELECTABLE.
  688. *************************************************************************************/
  689.  
  690. void
  691. CScrollList::Hilite( short theCell, Boolean hiliteFlag)
  692.  
  693. {
  694.     LongRect    pixels;
  695.     Rect        visPixels;
  696.     
  697.     if ( !printing && SELECTABLE && !(hiliteFlag && (fEditing || fStillEditing)) )
  698.     {
  699.         CellsToPixels( theCell, theCell, &pixels);
  700.         if ( SectAperture( &pixels, &visPixels) )
  701.         {
  702.             SetHiliteMode();                // invert with user's hilite color
  703.             InvertRect( &visPixels);
  704.         }
  705.     }
  706.  
  707. }  /* CScrollList::Hilite */
  708.  
  709.  
  710. /*************************************************************************************
  711.  RefreshCell
  712.  
  713.     Force an update event for the specified cell.
  714. *************************************************************************************/
  715.  
  716. void
  717. CScrollList::RefreshCell( short aCell)
  718.  
  719. {
  720.     LongRect    r;
  721.     
  722.     if ( aCell > 0 && aCell <= numCells )
  723.     {
  724.         GetCellRect( aCell, &r);
  725.         RefreshLongRect( &r);
  726.     }
  727.  
  728. }  /* CScrollList::RefreshCell */
  729.  
  730.  
  731. /*************************************************************************************
  732.  RefreshCellRange
  733.  
  734.     Force an update event for the specified range of cells.
  735. *************************************************************************************/
  736.  
  737. void
  738. CScrollList::RefreshCellRange( short firstCell, short lastCell)
  739.  
  740. {
  741.     LongRect    cellPixels;
  742.     Rect        visArea;
  743.     
  744.     if ( CellsToPixels( firstCell, lastCell, &cellPixels) )
  745.     {
  746.         if ( SectAperture( &cellPixels, &visArea) )
  747.             InvalRect( &visArea);
  748.     }
  749.  
  750. }  /* CScrollList::RefreshCellRange */
  751.  
  752.  
  753. /*************************************************************************************
  754.  GetCellHeight
  755.  
  756.     Return the height of each cell.
  757. *************************************************************************************/
  758.  
  759. short
  760. CScrollList::GetCellHeight( void)
  761.  
  762. {
  763.     return cellHeight;
  764.  
  765. }  /* CScrollList::GetCellHeight */
  766.  
  767.  
  768. /*************************************************************************************
  769.  GetNumCells
  770.  
  771.     Return the number of cells in the list.
  772. *************************************************************************************/
  773.  
  774. short
  775. CScrollList::GetNumCells( void)
  776.  
  777. {
  778.     return numCells;
  779.  
  780. }  /* CScrollList::GetNumCells */
  781.  
  782.  
  783. /*************************************************************************************
  784.  GetCellRect
  785.  
  786.     Determine the pixel area spanned by theCell.
  787. *************************************************************************************/
  788.  
  789. void
  790. CScrollList::GetCellRect( short theCell, LongRect *cellRect)
  791.  
  792. {
  793.     if ( theCell > 0 && theCell <= numCells )
  794.         SetLongRect( cellRect, 0, cellHeight * (theCell - 1), width, cellHeight * theCell);
  795.     else
  796.         SetLongRect( cellRect, 0, 0, 0, 0);
  797.  
  798. }  /* CScrollList::GetCellRect */
  799.  
  800.  
  801. /*************************************************************************************
  802.  PixelsToCells
  803.  
  804.     Find the range of cells that a pixel area covers.
  805.     
  806.     RETURNS true of it covers any cells at all.
  807. *************************************************************************************/
  808.  
  809. Boolean
  810. CScrollList::PixelsToCells( LongRect *pixelsRect, short *firstCell, short *lastCell)
  811.  
  812. {
  813.     short        fCell, lCell;
  814.     
  815.     fCell = FindHitCell( &topLeftL(*pixelsRect));
  816.     lCell = FindHitCell( &botRightL(*pixelsRect));
  817.     
  818.     if ( fCell > numCells || lCell < 1 || fCell > lCell )
  819.     {
  820.         *firstCell = 0;
  821.         *lastCell = 0;
  822.         return FALSE;
  823.     }
  824.     else
  825.     {
  826.         *firstCell = Max( fCell, 1);
  827.         *lastCell = Min( lCell, numCells);
  828.         return TRUE;
  829.     }
  830.  
  831. }  /* CScrollList::PixelsToCells */
  832.  
  833.  
  834. /*************************************************************************************
  835.  CellsToPixels
  836.  
  837.     Calculates the pixel area covered by a range of cells.
  838.     
  839.     RETURNS true if the range is valid.
  840. *************************************************************************************/
  841.  
  842. Boolean
  843. CScrollList::CellsToPixels( short firstCell, short lastCell, LongRect *pixelsRect)
  844.  
  845. {
  846.     if ( lastCell >= firstCell )
  847.     {
  848.         SetLongRect( pixelsRect, 0, cellHeight * (firstCell - 1),
  849.                      width, cellHeight * (lastCell));
  850.         return TRUE;
  851.     }
  852.     else
  853.     {
  854.         SetLongRect( pixelsRect, 0, 0, 0, 0);
  855.         return FALSE;
  856.     }
  857.  
  858. }  /* CScrollList::CellsToPixels */
  859.  
  860.  
  861. /*************************************************************************************
  862.  FindHitCell
  863.  
  864.     Find the cell that contains hitPt.
  865. *************************************************************************************/
  866.  
  867. short
  868. CScrollList::FindHitCell( LongPt *hitPt)
  869.  
  870. {
  871.     if ( (hitPt->h >= 0 && hitPt->h < width) &&
  872.             (hitPt->v >= 0 && hitPt->v < bounds.bottom * cellHeight) )
  873.         return (hitPt->v / cellHeight + 1);
  874.     else
  875.         return 0;
  876.  
  877. }  /* CScrollList::FindHitCell */
  878.  
  879.  
  880. /*************************************************************************************
  881.  ClickOutsideBounds
  882.  
  883.     Handle a click inside the frame but outside the list's bounds.
  884. *************************************************************************************/
  885.  
  886. void
  887. CScrollList::ClickOutsideBounds( Point hitPt, short modifierKeys, long when)
  888.  
  889. {
  890.     SelectCell( 0, kDoRedraw);
  891.  
  892. }  /* CScrollList::ClickOutsideBounds */
  893.  
  894.  
  895. /*************************************************************************************
  896.  SelectCell
  897.  
  898.     Deselects the previous selected cell if there is one and selects the new cell.
  899.     Doesn't reselect the same cell.  Handles all hiliting.
  900.     Use 0 for aCell to deselect all cells.
  901. *************************************************************************************/
  902.  
  903. void
  904. CScrollList::SelectCell( short aCell, Boolean reDraw)
  905.  
  906. {
  907.     tSelectionInfo        info;
  908.     
  909.     if ( aCell >= 0 && aCell <= numCells && aCell != selectedCell )
  910.     {
  911.         info.prevSelection = selectedCell;            // store change info
  912.         info.newSelection = aCell;
  913.         
  914.         if ( reDraw )
  915.         {
  916.             Prepare();
  917.             
  918.             if ( selectedCell )
  919.                 Hilite( selectedCell, FALSE);        // unhilite old selected cell
  920.             
  921.             selectedCell = aCell;                    // store new selected cell
  922.             
  923.             if ( aCell )
  924.                 Hilite( aCell, TRUE);                // hilite new selected cell
  925.         }
  926.         else                                        // just invalidate
  927.         {
  928.             if ( selectedCell )
  929.                 RefreshCell( selectedCell);
  930.             
  931.             selectedCell = aCell;                    // store new selected cell
  932.             
  933.             if ( aCell )
  934.                 RefreshCell( aCell);
  935.         }
  936.         
  937.         BroadcastChange( scrollListSelectionChanged, &info);
  938.     }
  939.  
  940. }  /* CScrollList::SelectCell */
  941.  
  942.  
  943. /*************************************************************************************
  944.  GetSelectedCell
  945.  
  946.     RETURNS the selected cell or zero if none.
  947. *************************************************************************************/
  948.  
  949. short
  950. CScrollList::GetSelectedCell( void)
  951.  
  952. {
  953.     return selectedCell;
  954.  
  955. }  /* CScrollList::GetSelectedCell */
  956.  
  957.  
  958. /*************************************************************************************
  959.  ScrollToSelection  {OVERRIDE}
  960.  
  961.     Scroll the selected cell into view.  Also tries to eliminate any empty space
  962.     between the last cell in the list and the bottom of the frame.
  963. *************************************************************************************/
  964.  
  965. void
  966. CScrollList::ScrollToSelection( void)
  967.  
  968. {
  969.     LongPt        selPos;
  970.     short        hSpan, vSpan;
  971.     
  972.     GetFrameSpan( &hSpan, &vSpan);                // get currently visible cell range
  973.     selPos = position;
  974.     
  975.     if ( selectedCell )
  976.     {
  977.         if ( selectedCell <= selPos.v )
  978.             selPos.v = selectedCell - 1;
  979.         else if ( selectedCell > selPos.v + vSpan )
  980.             selPos.v = selectedCell - vSpan;
  981.     }
  982.             // try to minimize unsightly empty space at bottom of list frame
  983.     
  984.     if ( selPos.v + vSpan > numCells )
  985.         selPos.v = Max( 0, numCells - vSpan);
  986.     
  987.     if ( selPos.v != position.v )                // only scroll if we actually moved
  988.         ScrollTo( &selPos, TRUE);
  989.  
  990. }  /* CScrollList::ScrollToSelection */
  991.  
  992.  
  993. /*************************************************************************************
  994.  DoKeyDown  {OVERRRIDE}
  995.  
  996.     Handle moving the selected cell up or down one space.  If command key is
  997.     down, move to top/bottom of list appropriately.
  998. *************************************************************************************/
  999.  
  1000. void
  1001. CScrollList::DoKeyDown( char theChar, Byte keyCode, EventRecord *macEvent)
  1002.  
  1003. {
  1004.     short        newCell = 0;
  1005.     short        currCell;
  1006.     Boolean        commandKey = ((macEvent->modifiers & cmdKey) != 0);
  1007.     
  1008.     if ( (keyCode == KeyUpCursor || keyCode == KeyDownCursor) && itsArray )
  1009.     {
  1010.         switch ( keyCode )
  1011.         {
  1012.             case  KeyUpCursor:
  1013.                 newCell = commandKey ? 1 : selectedCell > 1 ? selectedCell - 1 : 1;
  1014.                 break;
  1015.             
  1016.             case  KeyDownCursor:
  1017.                 newCell = commandKey ? numCells : selectedCell < numCells
  1018.                                      && selectedCell ? selectedCell + 1 : numCells;
  1019.                 break;
  1020.         }
  1021.         
  1022.         if ( newCell != selectedCell )
  1023.         {
  1024.             SelectCell( newCell, TRUE);                // select and display new cell
  1025.             ScrollToSelection();
  1026.         }
  1027.     }
  1028.     else if ( EDITABLE && itsArray )
  1029.     {
  1030.                 // Handle keystrokes to initiate adding, deleting, and editing
  1031.                 // of the selected cell.
  1032.     
  1033.         switch ( theChar )
  1034.         {
  1035.             case  kEscapeOrClear:
  1036.             case  kDeleteKey:
  1037.                 DoDeleteCell();
  1038.                 break;
  1039.             
  1040.             case  kEnterKey:
  1041.                 DoModifyCell();
  1042.                 break;
  1043.             
  1044.             case  kReturnKey:
  1045.                 DoAddCell();
  1046.                 break;
  1047.             
  1048.             default:
  1049.                 inherited::DoKeyDown( theChar, keyCode, macEvent);
  1050.                 break;
  1051.         }
  1052.     }
  1053.     else
  1054.         inherited::DoKeyDown( theChar, keyCode, macEvent);
  1055.  
  1056. }  /* CScrollList::DoKeyDown */
  1057.  
  1058.  
  1059. /*************************************************************************************
  1060.  DoAutoKey  {OVERRRIDE}
  1061.  
  1062.     Bottleneck right through DoKeyDown.
  1063. *************************************************************************************/
  1064.  
  1065. void
  1066. CScrollList::DoAutoKey( char theChar, Byte keyCode, EventRecord *macEvent)
  1067.  
  1068. {
  1069.     DoKeyDown( theChar, keyCode, macEvent);
  1070.  
  1071. }  /* CScrollList::DoAutoKey */
  1072.  
  1073.  
  1074. /*************************************************************************************
  1075.  DoAddCell
  1076.  
  1077.     Add a new cell after the selected cell.  If no cell is selected, append it
  1078.     onto the end of the list.  Immediately calls DoModifyCell after adding.
  1079. *************************************************************************************/
  1080.  
  1081. void
  1082. CScrollList::DoAddCell( void)
  1083.  
  1084. {
  1085.     short        newCell;
  1086.     
  1087.     ScrollToSelection();
  1088.     
  1089.     if ( fEditing )
  1090.     {
  1091.         DoAddAnotherCell();
  1092.         return;
  1093.     }
  1094.     
  1095.     if ( selectedCell < 1 )                        // choose new cell position
  1096.         newCell = numCells + 1;
  1097.     else
  1098.         newCell = selectedCell + 1;
  1099.     
  1100.     SelectCell( 0, kDoRedraw);                    // get rid of hiliting on old cell
  1101.     DoInsertCell( newCell);                        // create the blank new cell
  1102.     SelectCell( newCell, kDontRedraw);            // select new cell
  1103.     ScrollToSelection();
  1104.     
  1105.     DoModifyCell();
  1106.  
  1107. }  /* CScrollList::DoAddCell */
  1108.  
  1109.  
  1110. /*************************************************************************************
  1111.  DoAddAnotherCell
  1112.  
  1113.     Add a new cell after the selected cell.  Used when use does add cell while
  1114.     still editing a cell.
  1115. *************************************************************************************/
  1116.  
  1117. void
  1118. CScrollList::DoAddAnotherCell( void)
  1119.  
  1120. {
  1121.     short        newCell;
  1122.     
  1123.     newCell = selectedCell + 1;                    // choose new cell position
  1124.     
  1125.     fStillEditing = TRUE;
  1126.     this->BecomeGopher( TRUE);                    // finish editing
  1127.     fStillEditing = FALSE;
  1128.     
  1129.     fEditing = TRUE;
  1130.     DoInsertCell( newCell);                        // create the blank new cell
  1131.     SelectCell( newCell, kDontRedraw);            // select new cell
  1132.     ScrollToSelection();
  1133.     
  1134.     BeginEditing();
  1135.  
  1136. }  /* CScrollList::DoAddAnotherCell */
  1137.  
  1138.  
  1139. /*************************************************************************************
  1140.  DoModifyCell
  1141.  
  1142.     Modify the selected cell, if there is one.  Makes the appropriate call to
  1143.     BeginEditing.
  1144. *************************************************************************************/
  1145.  
  1146. void
  1147. CScrollList::DoModifyCell( void)
  1148.  
  1149. {
  1150.     ScrollToSelection();
  1151.     
  1152.     if ( fEditing )
  1153.     {
  1154.         this->BecomeGopher( TRUE);
  1155.         return;
  1156.     }
  1157.     
  1158.     if ( selectedCell < 1 || selectedCell > numCells )
  1159.         return;
  1160.     
  1161.     Hilite( selectedCell, FALSE);
  1162.     BeginEditing();
  1163.  
  1164. }  /* CScrollList::DoModifyCell */
  1165.  
  1166.  
  1167. /*************************************************************************************
  1168.  DoDeleteCell
  1169.  
  1170.     Delete the selected cell if there is one.  Sends message to array so the
  1171.     array will send a change message to us.
  1172. *************************************************************************************/
  1173.  
  1174. void
  1175. CScrollList::DoDeleteCell( void)
  1176.  
  1177. {
  1178.     if ( fEditing )
  1179.         this->BecomeGopher( TRUE);
  1180.     
  1181.     if ( selectedCell )
  1182.         itsArray->DeleteItem( selectedCell);
  1183.  
  1184. }  /* CScrollList::DoDeleteCell */
  1185.  
  1186.  
  1187. /*************************************************************************************
  1188.  DoInsertCell
  1189.  
  1190.     Insert a blank cell before beforeCell.  Default does nothing.  Subclass method
  1191.     should create a new block and call itsArray->InsertAtIndex( &data, beforeCell).
  1192.     
  1193.         OVERRIDE this method.
  1194. *************************************************************************************/
  1195.  
  1196. void
  1197. CScrollList::DoInsertCell( short beforeCell)
  1198.  
  1199. {
  1200.  
  1201. }  /* CScrollList::DoInsertCell */
  1202.  
  1203.  
  1204. /*************************************************************************************
  1205.  BeginEditing
  1206.  
  1207.     Setup for editing the selected cell.  Default only sets the editing flag.
  1208.     Subclasses should create any subpanes needed to edit the selected cell.
  1209.     Call this method after setting up subpanes.
  1210.     
  1211.         OVERRIDE this method.
  1212. *************************************************************************************/
  1213.  
  1214. void
  1215. CScrollList::BeginEditing( void)
  1216.  
  1217. {
  1218.     SetupCellData();
  1219.     fEditing = TRUE;
  1220.  
  1221. }  /* CScrollList::BeginEditing */
  1222.  
  1223.  
  1224. /*************************************************************************************
  1225.  DoneEditing
  1226.  
  1227.     The user has finished editing the cell.  Default resets the editing flag.
  1228.     Subclasses should call the inherited method and then remove any subpanes
  1229.     that they added for editing.
  1230.     
  1231.         OVERRIDE this method.
  1232. *************************************************************************************/
  1233.  
  1234. void
  1235. CScrollList::DoneEditing( void)
  1236.  
  1237. {
  1238.     LongRect     cellRect;
  1239.     Rect        qdRect;
  1240.     
  1241.     fEditing = FALSE;
  1242.     RetrieveCellData();
  1243.     
  1244. /*    Prepare();
  1245.     GetCellRect( selectedCell, &cellRect);                    // Redraw the cell
  1246.     FrameToQDR( &cellRect, &qdRect);
  1247.     
  1248.     EraseRect( &qdRect);
  1249.     DrawCell( selectedCell, &qdRect);
  1250.     ValidRect( &qdRect);
  1251.     
  1252.     if ( !fStillEditing )
  1253.         Hilite( selectedCell, TRUE);
  1254. */
  1255. }  /* CScrollList::DoneEditing */
  1256.  
  1257.  
  1258. /*************************************************************************************
  1259.  SetupCellData
  1260.  
  1261.     Get the cell data from the array and place it into editing subpanes.
  1262.     Default does nothing.
  1263.     
  1264.         OVERRIDE this method.
  1265. *************************************************************************************/
  1266.  
  1267. void
  1268. CScrollList::SetupCellData( void)
  1269.  
  1270. {
  1271.  
  1272. }  /* CScrollList::SetupCellData */
  1273.  
  1274.  
  1275. /*************************************************************************************
  1276.  RetrieveCellData
  1277.  
  1278.     Retrieve the edited cell data from the editing supanes and place it back into
  1279.     the array.  Default does nothing.
  1280.     
  1281.         OVERRIDE this method.
  1282. *************************************************************************************/
  1283.  
  1284. void
  1285. CScrollList::RetrieveCellData( void)
  1286.  
  1287. {
  1288.  
  1289. }  /* CScrollList::RetrieveCellData */
  1290.  
  1291.  
  1292. /*************************************************************************************
  1293.  SetDrawActiveBorder
  1294.  
  1295.     Specify whether or not the list has an active border.
  1296. *************************************************************************************/
  1297.  
  1298. void
  1299. CScrollList::SetDrawActiveBorder( Boolean fDrawActiveBorder)
  1300.  
  1301. {
  1302.     drawActiveBorder = fDrawActiveBorder;
  1303.  
  1304. }  /* CScrollList::SetDrawActiveBorder */
  1305.  
  1306.  
  1307. /*************************************************************************************
  1308.  BecomeGopher  {OVERRIDE}
  1309.  
  1310.     If we are becoming the gopher, and drawActiveBorder is true, draw a two pixel
  1311.     thick border around the scroll pane.
  1312.     If we are losing our gophership, remove any border around the scroll pane.
  1313. *************************************************************************************/
  1314.  
  1315. Boolean
  1316. CScrollList::BecomeGopher( Boolean fBecoming)
  1317.  
  1318. {
  1319.     if ( itsArray == NULL && fBecoming )
  1320.         return FALSE;
  1321.     
  1322.     if ( !inherited::BecomeGopher( fBecoming) )
  1323.         return FALSE;
  1324.     
  1325.     if ( drawActiveBorder && itsScrollPane )
  1326.         MakeBorder();
  1327.     
  1328.     return TRUE;
  1329.  
  1330. }  /* CScrollList::BecomeGopher */
  1331.  
  1332.  
  1333. /*************************************************************************************
  1334.  MakeBorder
  1335.  
  1336.     Create a border or take it away based on fActive.
  1337. *************************************************************************************/
  1338.  
  1339. void
  1340. CScrollList::MakeBorder( void)
  1341.  
  1342. {
  1343.     CPaneBorder     *border;
  1344.     Rect            margin;
  1345.     
  1346.     if ( (active && gGopher == this) || fEditing )
  1347.     {
  1348.         if ( !itsScrollPane->GetBorder() )
  1349.         {
  1350.             border = new( CPaneBorder);
  1351.             border->IPaneBorder( kBorderFrame);
  1352.             SetRect( &margin, -kBorderMargin, -kBorderMargin,
  1353.                         kBorderMargin, kBorderMargin);
  1354.             border->SetPenSize( kBorderPen, kBorderPen);
  1355.             border->SetMargin( &margin);
  1356.             
  1357.             itsScrollPane->SetBorder( border);
  1358.         }
  1359.     }
  1360.     else
  1361.         itsScrollPane->SetBorder( NULL);
  1362.  
  1363. }  /* CScrollList::MakeBorder */
  1364.  
  1365.  
  1366. /*************************************************************************************
  1367.  Activate  {OVERRRIDE}
  1368.  
  1369.     Hilite the selected cell, if there is one.
  1370. *************************************************************************************/
  1371.  
  1372. void
  1373. CScrollList::Activate( void)
  1374. {
  1375.     if ( !active )
  1376.     {
  1377.         Prepare();
  1378.         Hilite( selectedCell, TRUE);
  1379.     }
  1380.     
  1381.     if ( drawActiveBorder && itsScrollPane )
  1382.         MakeBorder();
  1383.     
  1384.     inherited::Activate();
  1385.  
  1386. }  /* CScrollList::Activate */
  1387.  
  1388.  
  1389. /*************************************************************************************
  1390.  Deactivate  {OVERRRIDE}
  1391.  
  1392.     Unhilite the selected cell, if there is one.
  1393. *************************************************************************************/
  1394.  
  1395. void
  1396. CScrollList::Deactivate( void)
  1397.  
  1398. {
  1399.     if ( active )
  1400.     {
  1401.         if ( fEditing )
  1402.             this->BecomeGopher( TRUE);
  1403.         
  1404.         Prepare();
  1405.         Hilite( selectedCell, FALSE);
  1406.     }
  1407.     
  1408.     if ( drawActiveBorder && itsScrollPane )
  1409.         MakeBorder();
  1410.     
  1411.     inherited::Deactivate();
  1412.  
  1413. }  /* CScrollList::Deactivate */
  1414.  
  1415.  
  1416. /*************************************************************************************
  1417.  Dispose  {OVERRRIDE}
  1418.  
  1419.     Dispose of the array of checks, if it exists.  ====
  1420. *************************************************************************************/
  1421.  
  1422. void
  1423. CScrollList::Dispose( void)
  1424.  
  1425. {
  1426.     ForgetObject( itsChecks);
  1427.     inherited::Dispose();
  1428.  
  1429. }  /* CScrollList::Dispose */
  1430.  
  1431.  
  1432. /*************************************************************************************
  1433.  SetArray
  1434.  
  1435.     Associate a new array with this scroll list.  If anArray is NULL, don't allow
  1436.     this list to become the gopher.
  1437. *************************************************************************************/
  1438.  
  1439. void
  1440. CScrollList::SetArray( CArray *anArray)
  1441.  
  1442. {
  1443.     short        deltaRows;
  1444.     LongPt        topLeft;
  1445.     
  1446.     if ( itsArray )
  1447.     {
  1448.         CancelDependency( itsArray);
  1449.         ForgetObject( itsChecks);
  1450.         SetLongPt( &topLeft, 0, 0);
  1451.         ScrollTo( &topLeft, kNoRedraw);
  1452.     }
  1453.     
  1454.     itsArray = anArray;
  1455.     SetCanBeGopher( anArray != NULL);
  1456.     
  1457.     if ( anArray )
  1458.     {
  1459.         DependUpon( itsArray);
  1460.         selectedCell = 0;
  1461.         
  1462.                 // adjust the list to have the same cells as the array
  1463.         
  1464.         deltaRows = itsArray->GetNumItems() - numCells;
  1465.         
  1466.         if ( deltaRows > 0 )
  1467.             AddCell( deltaRows, numCells);
  1468.         else if ( deltaRows < 0 )
  1469.             DeleteCell( -deltaRows, numCells + deltaRows + 1);
  1470.     
  1471.         if ( CHECKABLE )
  1472.         {
  1473.             itsChecks = new CStateArray;
  1474.             itsChecks->IStateArray( numCells, 0);
  1475.         }
  1476.     }
  1477.     else
  1478.     {
  1479.         numCells = 0;
  1480.         selectedCell = 0;
  1481.         AdjustBounds();
  1482.     }
  1483.     
  1484.     Refresh();
  1485.  
  1486. }  /* CScrollList::SetArray */
  1487.  
  1488. /*************************************************************************************
  1489.  GetArray
  1490.  
  1491.     Return a reference to itsArray.
  1492. *************************************************************************************/
  1493.  
  1494. CArray *
  1495. CScrollList::GetArray( void)
  1496.  
  1497. {
  1498.     return itsArray;
  1499.  
  1500. }  /* CScrollList::GetArray */
  1501.  
  1502.  
  1503. /*************************************************************************************
  1504.  ProviderChanged
  1505.  
  1506.     Handle a change to itsArray.
  1507. *************************************************************************************/
  1508.  
  1509. void
  1510. CScrollList::ProviderChanged( CCollaborator *aProvider, long reason, void* info)
  1511.  
  1512. {
  1513.     tMovedElementInfo    *moveInfo;
  1514.     short                firstCell, lastCell;
  1515.     long                infoIndex = *(long*) info;
  1516.     short                state = 0;
  1517.     
  1518.     if ( aProvider == itsArray )
  1519.     {
  1520.         switch( reason )
  1521.         {
  1522.             case  arrayInsertElement:            // add a new cell
  1523.                 if ( CHECKABLE )
  1524.                     itsChecks->InsertAtIndex( &state, infoIndex);
  1525.                 
  1526.                 AddCell( 1, infoIndex-1);
  1527.                 break;
  1528.                 
  1529.                 
  1530.             case  arrayDeleteElement:            // delete its cell
  1531.                 if ( CHECKABLE )
  1532.                     itsChecks->DeleteItem( infoIndex);
  1533.                 
  1534.                 DeleteCell( 1, infoIndex);
  1535.                 break;
  1536.                 
  1537.                 
  1538.             case  arrayMoveElement:                // redraw all cells encompassing
  1539.                                                 // its old and new positions
  1540.                 moveInfo = (tMovedElementInfo *) info;
  1541.                 
  1542.                 if ( CHECKABLE )
  1543.                     itsChecks->MoveItemToIndex( moveInfo->originalIndex,
  1544.                                                 moveInfo->newIndex);
  1545.                 
  1546.                 firstCell = Min( moveInfo->originalIndex, moveInfo->newIndex);
  1547.                 lastCell = Max( moveInfo->originalIndex, moveInfo->newIndex);
  1548.                 RefreshCellRange( firstCell, lastCell);
  1549.                 break;
  1550.                 
  1551.                 
  1552.             case arrayElementChanged:            // redraw its cell
  1553.                 {
  1554.                     LongRect    cellRect;
  1555.                     Rect        visArea;
  1556.                     
  1557.                     Prepare();
  1558.                     GetCellRect( infoIndex, &cellRect);
  1559.                     if ( SectAperture( &cellRect, &visArea) )
  1560.                     {
  1561.                         EraseRect( &visArea);
  1562.                         DrawCell( infoIndex, &visArea);
  1563.                         if ( infoIndex == selectedCell )
  1564.                             Hilite( selectedCell, TRUE);
  1565.                         ValidRect( &visArea);
  1566.                     }
  1567.                 }
  1568.                 
  1569. //                RefreshCell( infoIndex);
  1570.                 break;    
  1571.                 
  1572.                 
  1573.             default:
  1574.                 inherited::ProviderChanged( aProvider, reason, info);
  1575.                 break;            
  1576.         }
  1577.     }
  1578.     else
  1579.         inherited::ProviderChanged( aProvider, reason, info);
  1580.  
  1581. }  /* CScrollList::ProviderChanged */
  1582.