home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / central / mfinder.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  46.9 KB  |  2,069 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "mfinder.h"
  20. #include "macutil.h"
  21. #include "miconutils.h"
  22. #include "macgui.h"
  23. #include "resgui.h"
  24.  
  25. #include "UStdBevels.h"
  26.  
  27. const Int32 kOutsideSlop = 0x80008000;
  28.  
  29. extern void HiliteRect( const Rect& r );
  30.  
  31. // pkc (6/14/96) Set sTruncChar to 0 initially
  32. static unsigned char sTruncChar = 0;
  33.  
  34. LFinderHeader::LFinderHeader( LStream* inStream ):
  35.     LView( inStream )
  36. {
  37.     fTextTraits = 130;
  38.     fFinder = NULL;
  39. }
  40.  
  41. void LFinderHeader::DrawColumn( UInt16 column )
  42. {
  43.     CStr255        text;
  44.     Rect        columnRect;
  45.     Style        style;
  46.     
  47.     if ( fFinder )
  48.     {
  49.         UGraphics::SetFore( CPrefs::Black );
  50.         
  51.         ::PmBackColor(eStdGray86);
  52.         ::PenPat( &qd.black );
  53.  
  54.         fFinder->GetColumnTitle( column, text );
  55.         fFinder->GetColumnRect( 1, column, columnRect );
  56.         columnRect.top = 0;
  57.         columnRect.bottom = mFrameSize.height;
  58.         if ( ( columnRect.right - columnRect.left ) > 2 )
  59.         {
  60.             ::EraseRect( &columnRect );
  61.             Rect        tmp;
  62.             
  63.             tmp.top = columnRect.top;
  64.             tmp.right = columnRect.right - 2;
  65.             tmp.left = columnRect.left + 2;
  66.             tmp.bottom = columnRect.bottom;
  67.             
  68.             if ( text[ 1 ] == '#' )
  69.             {
  70.                 Int32        resID;
  71.                 Handle        iconSuite;
  72.                 
  73.                 myStringToNum( text, &resID ); 
  74.                 iconSuite = CIconList::GetIconSuite( resID );
  75.                 if ( iconSuite )
  76.                 {
  77.                     tmp.right = tmp.left + 16;
  78.                     if ( columnRect.right - columnRect.left > 16 )
  79.                         fFinder->DrawIcon( iconSuite, FALSE, tmp );
  80.                 }
  81.             }
  82.             else
  83.             {
  84.                 style = fFinder->ColumnTextStyle( column );
  85.                 fFinder->DrawText( style, text, tmp, smTruncEnd, fTextTraits, tmp.bottom - 2 );
  86.             }
  87.             FrameButton( columnRect, FALSE );
  88.         }
  89.     }
  90. }
  91.  
  92. void LFinderHeader::DrawSelf()
  93. {
  94.     UInt16        columns;
  95.     
  96.     if ( !fFinder )
  97.         return;
  98.         
  99.     columns = fFinder->GetNumberOfColumns();
  100.     
  101.     UTextTraits::SetPortTextTraits( fTextTraits );
  102.  
  103.     for ( UInt16 i = 0; i < columns; i++ )
  104.         DrawColumn( i );
  105. }
  106.  
  107. void LFinderHeader::ClickSelf( const SMouseDownEvent& where )
  108. {
  109.     Int16        column;
  110.     
  111.     column = fFinder->InResizableColumnBar( where.whereLocal );
  112.     
  113.     if ( column != NO_COLUMN )
  114.         fFinder->TrackResizeColumn( where, 1, column );
  115.     else
  116.     {
  117.         column = fFinder->InColumn( where.whereLocal );
  118.         if ( column != NO_COLUMN )
  119.             this->TrackReorderColumns( where, column );
  120.     }
  121. }
  122.  
  123. void LFinderHeader::TrackReorderColumns( const SMouseDownEvent& where,
  124.     UInt16 column )
  125. {
  126.     Point            whereP;
  127.     Rect            columnRect;
  128.     Rect            viewRect;
  129.     RgnHandle        myRgn;
  130.     Int16            delta;
  131.     Int32            result;
  132.     Int16            endColumn;
  133.     
  134.     if ( !this->FocusDraw() )
  135.         return;
  136.     
  137.     whereP = where.whereLocal;
  138.     fFinder->GetColumnRect( 1, column, columnRect );
  139.     this->CalcLocalFrameRect( viewRect );
  140.     
  141.     if (    LDragAndDrop::DragAndDropIsPresent() && 
  142.             ::WaitMouseMoved( where.macEvent.where ) )
  143.     {
  144.         columnRect.top = viewRect.top++;
  145.         columnRect.bottom = viewRect.bottom--;
  146.         myRgn = ::NewRgn();
  147.         ::RectRgn( myRgn, &columnRect );
  148.         
  149.         result = ::DragGrayRgn(    myRgn, whereP, 
  150.                     &viewRect, &viewRect, hAxisOnly, NULL );        
  151.     
  152.         ::DisposeRgn( myRgn );
  153.     
  154.         delta = LoWord( result );
  155.         if ( ( result == kOutsideSlop ) || ( delta == 0 ) ) 
  156.             return;
  157.     
  158.         whereP.h += delta;
  159.         endColumn = fFinder->InColumn( whereP );
  160.         if ( endColumn != NO_COLUMN && endColumn != column )
  161.             fFinder->SwapColumns( endColumn, column );
  162.     }
  163.     else
  164.         fFinder->SortByColumnNumber( column, (where.macEvent.modifiers & optionKey) != 0 );
  165. }
  166.  
  167. void LFinderHeader::AdjustCursorSelf( Point inPortPt, const EventRecord& inMacEvent )
  168. {
  169.     Int16         i;
  170.  
  171.     PortToLocalPoint( inPortPt );
  172.     i = fFinder->InResizableColumnBar( inPortPt );
  173.  
  174.     if ( i != NO_COLUMN )
  175.         ::SetCursor( *(::GetCursor( curs_HoriDrag ) ) );
  176.     else
  177.         LView::AdjustCursorSelf( inPortPt, inMacEvent );
  178. }
  179.  
  180.  
  181.  
  182.  
  183. LFinderView::LFinderView( LStream* inStream ):
  184.     LView( inStream ),
  185.     LDragAndDrop( GetMacPort(), this )
  186. {
  187.     fTextTraits = 130;
  188.     for ( long i = 0; i < NUM_COLUMNS; i++ )
  189.     {
  190.         fColumnOffsets[ i ] = 0;
  191.         fColumnIDs[ i ] = 0;
  192.     }
  193.     
  194.     fNumberColumns = 1;
  195.     fClipImage = FALSE;
  196.     fAllowsRectSelection = TRUE;    
  197.     fAllowsKeyNavigation = TRUE;
  198.     fHighlightRow = TRUE;
  199.     fHeader = NULL;
  200.     fForeColor.red = fForeColor.green = fForeColor.blue = 0x0000;// black
  201.     fBackColor.red = fBackColor.green = fBackColor.blue = 0xFFFF;// white 
  202.     this->CaculateFontRect();
  203. }
  204.  
  205. void LFinderView::CaculateFontRect()
  206. {
  207.     FontInfo        fontInfo;
  208.     UInt16            fontHeight;
  209.     
  210.     fontInfo = SafeGetFontInfo( fTextTraits );
  211.     fontHeight = fontInfo.ascent + fontInfo.descent + fontInfo.leading;
  212.     fCellHeight = fontHeight < 16 ? 16 : fontHeight;
  213.     fBaseline = fCellHeight - fontInfo.descent + fontInfo.leading;
  214. }
  215.  
  216. void LFinderView::FinishCreateSelf()
  217. {
  218.     LView::FinishCreateSelf();
  219.     
  220.     LFinderHeader*        header = NULL;
  221.     char                id[ 4 ];
  222.     PaneIDT                paneID;
  223.         
  224.     *((PaneIDT*)id) = mPaneID;
  225.     id[ 0 ] = 'H';
  226.     paneID = *((PaneIDT*)id);
  227.     header = (LFinderHeader*)mSuperView->FindPaneByID( paneID );
  228.     if ( header )
  229.         header->SetFinderView( this );
  230.     fHeader = header;
  231. }
  232.         
  233. void LFinderView::ResizeFrameBy( Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh )
  234. {
  235.     LView::ResizeFrameBy( inWidthDelta, inHeightDelta, inRefresh );
  236.     if ( fClipImage )
  237.     {
  238.         SDimension16        frameSize;
  239.             
  240.         this->GetFrameSize( frameSize );
  241.         this->ResizeImageTo( frameSize.width, mImageSize.height, inRefresh );
  242.     }
  243. }
  244.  
  245. // ÑÑ activate/deactivate feedback
  246. void LFinderView::ActivateSelf()
  247. {
  248.     LView::ActivateSelf();
  249.     RefreshSelectedCells();
  250. }
  251.  
  252. void LFinderView::DeactivateSelf()
  253. {
  254.     LView::DeactivateSelf();
  255.     RefreshSelectedCells();
  256. }
  257.  
  258. void LFinderView::RefreshSelectedCells()
  259. {
  260.     UInt32        topCell;
  261.     UInt32        bottomCell;
  262.     
  263.     GetVisibleCells( topCell, bottomCell );
  264.     if ( topCell == NO_CELL )
  265.         return;
  266.         
  267.     for ( UInt32 cell = topCell; cell <= bottomCell; cell++ )
  268.     {
  269.         if ( this->IsCellSelected( cell ) )    // For each selected cell, add the outline to the region
  270.             RefreshCells( cell, cell, FALSE );
  271.     }
  272. }
  273.  
  274. Boolean LFinderView::ObeyCommand( CommandT inCommand, void* ioParam )
  275. {
  276.     switch ( inCommand )
  277.     {
  278.         case msg_TabSelect:
  279.             if ( !IsEnabled() )
  280.                 return FALSE;
  281.             else
  282.                 return TRUE;
  283.         break;
  284.     }
  285.     return LCommander::ObeyCommand( inCommand, ioParam );
  286. }
  287.  
  288. // ÑÑ drawing/events
  289. Boolean LFinderView::HandleKeyPress( const EventRecord& inEvent )
  290. {
  291.     Char16        key = inEvent.message;
  292.     Char16        character = key & charCodeMask;
  293.  
  294.     if ( fAllowsKeyNavigation )
  295.     {
  296.         switch ( character )
  297.         {
  298.             case char_UpArrow:        this->KeyUp( inEvent );        return TRUE;
  299.             case char_DownArrow:    this->KeyDown( inEvent );    return TRUE;
  300.             case char_Home:            this->KeyHome( inEvent );    return TRUE;
  301.             case char_End:            this->KeyEnd( inEvent );    return TRUE;
  302.             case char_PageUp:        this->KeyPageUp( inEvent );    return TRUE;
  303.             case char_PageDown:        this->KeyPageDown( inEvent );    return TRUE;
  304.             case char_Return:
  305.             case char_Enter:        this->KeyEnter( inEvent );    return TRUE;
  306.         }
  307.     }
  308.     return LCommander::HandleKeyPress( inEvent );
  309. }
  310.  
  311. void LFinderView::KeyUp( const EventRecord& event )
  312. {
  313.     UInt32        cell;
  314.  
  315.     cell = this->FirstSelectedCell();
  316.     
  317.     if ( cell > 1 )
  318.         this->SelectItem( event, cell - 1, TRUE ); 
  319. }
  320.  
  321. void LFinderView::KeyDown( const EventRecord& event )
  322. {
  323.     UInt32        cell;
  324.     
  325.     cell = this->FirstSelectedCell();
  326.     
  327.     if ( cell < this->GetVisibleCount() )
  328.         this->SelectItem( event, cell + 1, TRUE );
  329. }
  330.  
  331. void LFinderView::KeyEnter( const EventRecord& event )
  332. {
  333.     UInt32        cell;
  334.     
  335.     cell = this->FirstSelectedCell();
  336.     
  337.     if ( cell > 0 )
  338.         this->DoDoubleClick( cell, event );
  339. }
  340.  
  341. void LFinderView::KeyHome( const EventRecord& event )
  342. {
  343.     if ( this->GetVisibleCount() > 0 )
  344.         this->SelectItem( event, 1, TRUE );
  345. }
  346.  
  347. void LFinderView::KeyEnd( const EventRecord& event )
  348. {
  349.     if ( this->GetVisibleCount() > 0 )
  350.         this->SelectItem( event, this->GetVisibleCount(), TRUE );
  351. }
  352.  
  353. void LFinderView::KeyPageUp( const EventRecord& /*event*/ )
  354. {
  355. }
  356.  
  357. void LFinderView::KeyPageDown( const EventRecord& /*event*/ )
  358. {
  359. }
  360.  
  361. Boolean LFinderView::ColumnText( UInt32 /*cell*/, UInt16 /*column*/, CStr255& text )
  362. {
  363.     text = CStr255::sEmptyString;
  364.     
  365.     return FALSE;
  366. }
  367.  
  368. // Figure out what cells have been exposed, and draw them
  369. void LFinderView::DrawSelf()
  370. {
  371.     RgnHandle    localUpdateRgnH;
  372.     Rect        updateRect;
  373.     UInt32        topCell;
  374.     UInt32        bottomCell;
  375.     SPoint32    tl;
  376.     SPoint32    br;
  377.     
  378.     localUpdateRgnH = GetLocalUpdateRgn();
  379.     updateRect = (**localUpdateRgnH).rgnBBox;
  380.     DisposeRgn( localUpdateRgnH );
  381.     
  382.     this->LocalToImagePoint( topLeft( updateRect ), tl );
  383.     this->LocalToImagePoint( botRight( updateRect ), br );
  384.     
  385.     topCell = FetchCellAt( tl );
  386.     bottomCell = FetchCellAt( br );
  387.     
  388.     ::EraseRect(&updateRect);
  389.     if ( topCell == NO_CELL )
  390.         return;
  391.         
  392.     if ( bottomCell >= topCell )
  393.     {
  394.         UTextTraits::SetPortTextTraits( fTextTraits );
  395.         for ( UInt32 i = topCell; i <= bottomCell; i++ )
  396.             DrawCellAt( i );
  397.     }
  398. }
  399.  
  400. void LFinderView::RefreshCells( Int32 first, Int32 last, Boolean rightAway )
  401. {
  402.     if ( rightAway && FocusDraw() && IsVisible() )
  403.     {
  404.         UTextTraits::SetPortTextTraits( fTextTraits );
  405.  
  406.         if ( first < 1 )
  407.             first = 1;
  408.  
  409.         if ( last > this->GetVisibleCount() )
  410.             last = this->GetVisibleCount();
  411.             
  412.         for ( Int32 i = first; i <= last; i++ )
  413.             DrawCellAt( i );
  414.     }
  415.     else if    ( FocusDraw() & IsVisible())
  416.     {
  417.         Rect            refresh;
  418.         
  419.         Rect            r1;
  420.         this->GetCellRect( first, r1 );
  421.  
  422.         refresh.top = r1.top;
  423.         refresh.left = 0;
  424.         refresh.right = r1.right;
  425.  
  426.         if ( last == LAST_CELL )
  427.         {
  428.             SPoint32        bigImageSize;
  429.             Point            imageSize;
  430.  
  431.             bigImageSize.v = mImageSize.height;
  432.             bigImageSize.h = mImageSize.width;
  433.         
  434.             this->ImageToLocalPoint( bigImageSize, imageSize );
  435.             refresh.bottom = imageSize.v;
  436.             refresh.right = imageSize.h;
  437.         }
  438.         else
  439.         {
  440.             Rect        r2;
  441.             this->GetCellRect( last, r2 );
  442.             refresh.bottom = r2.bottom;
  443.         }
  444.         
  445.         ::InvalRect( &refresh );
  446.     }
  447. }
  448.  
  449. void LFinderView::RemoveColumn( UInt16 column )
  450. {
  451.     Int16        count;
  452.     UInt16        width;
  453.     
  454.     if ( column >= ( fNumberColumns - 1 ) )
  455.         width = mImageSize.width - fColumnOffsets[ column ];
  456.     else
  457.         width = fColumnOffsets[ column + 1 ] - fColumnOffsets[ column ];
  458.  
  459.     for ( count = column; count < ( fNumberColumns - 1 ); count++ )
  460.     {
  461.         fColumnIDs[ count ] = fColumnIDs[ count + 1 ];
  462.         fColumnOffsets[ count ] = fColumnOffsets[ count + 1 ] - width;
  463.     }
  464.     
  465.     fColumnIDs[ fNumberColumns - 1 ] = 0;
  466.     fColumnOffsets[ fNumberColumns - 1 ] = 0;
  467.     
  468.     fNumberColumns--;
  469. }
  470.  
  471. void LFinderView::RefreshHeader()
  472. {
  473.     if ( fHeader )
  474.         fHeader->Refresh();
  475. }
  476.  
  477. void LFinderView::InsertColumn( UInt16 before, UInt16 columnID, UInt16 width )
  478. {
  479.     Int16        count;
  480.     
  481.     for ( count = fNumberColumns; count > before; count-- )
  482.     {
  483.         fColumnIDs[ count ] = fColumnIDs[ count - 1 ];
  484.         fColumnOffsets[ count ] = fColumnOffsets[ count - 1 ] + width;
  485.     }
  486.     
  487.     fColumnIDs[ before ] = columnID;
  488.     
  489.     if ( before == fNumberColumns )
  490.         fColumnOffsets[ before ] = fColumnOffsets[ before - 1 ] + width;
  491.         
  492.     fNumberColumns++;
  493. }
  494.     
  495. void LFinderView::SwapColumns( UInt16 columnA, UInt16 columnB )
  496. {
  497.     if ( columnA != columnB )
  498.     {
  499.         Int16        width;
  500.         Int16        columnID;
  501.  
  502.         columnID = fColumnIDs[ columnB ];
  503.         if ( columnB >= ( fNumberColumns - 1 ) )
  504.             width = mImageSize.width - fColumnOffsets[ columnB ];
  505.         else
  506.             width = fColumnOffsets[ columnB + 1 ] - fColumnOffsets[ columnB ];
  507.  
  508.         this->RemoveColumn( columnB );
  509.         this->InsertColumn( columnA, columnID, width );
  510.         this->Refresh();
  511.         if ( fHeader )
  512.             fHeader->Refresh();
  513.     }
  514. }
  515.  
  516. #define SAVE_VERSION    25
  517. void LFinderView::SavePlace( LStream* inStream )
  518. {
  519.     WriteVersionTag( inStream, SAVE_VERSION );
  520.     inStream->WriteData( &fNumberColumns, sizeof( fNumberColumns ) );
  521.     
  522.     for ( Int16 i = 0; i < fNumberColumns; i++ )
  523.     {
  524.         inStream->WriteData( &fColumnOffsets[ i ], sizeof( fColumnOffsets[ 0 ] ) );
  525.         inStream->WriteData( &fColumnIDs[ i ], sizeof( fColumnIDs[ 0 ] ) );
  526.     }
  527. }
  528.  
  529. void LFinderView::RestorePlace( LStream* inStream )
  530. {
  531.     Int16        numColumns;
  532.     Int16        columnOffset;
  533.     Int16        columnID;
  534.     
  535.     if ( !ReadVersionTag( inStream, SAVE_VERSION ) )
  536.         return;
  537.  
  538.     inStream->ReadData( &numColumns, sizeof( fNumberColumns ) );
  539.     
  540.     XP_ASSERT( numColumns < NUM_COLUMNS );
  541.     
  542.     if ( numColumns < 1 || numColumns > NUM_COLUMNS )
  543.         return;
  544.         
  545.     for ( Int16 i = 0; i < numColumns; i++ )
  546.     {
  547.         inStream->ReadData( &columnOffset, sizeof( fColumnOffsets[ 0 ] ) );
  548.         inStream->ReadData( &columnID, sizeof( fColumnIDs[ 0 ] ) );
  549.         
  550.         fColumnOffsets[ i ] = columnOffset;
  551.         fColumnIDs[ i ] = columnID;
  552.     }
  553. }
  554.  
  555. Boolean LFinderView::DispatchClick( const SMouseDownEvent& where, UInt32 cell, Int16 column )
  556. {
  557.     Boolean            handled = FALSE;
  558.     
  559.     switch ( column )
  560.     {
  561.         case HIER_COLUMN:
  562.         {
  563.             Rect        rect;
  564.  
  565.             if ( cell == NO_CELL && fAllowsRectSelection )
  566.                 this->TrackSpace( where, cell );
  567.             else
  568.             {
  569.                 this->GetTextRect( cell, rect );
  570.                 if ( ::PtInRect( where.whereLocal, &rect ) )
  571.                     this->TrackCell( where, cell );
  572.                 else
  573.                 {
  574.                     this->GetIconRect( cell, rect );
  575.                     if ( ::PtInRect( where.whereLocal, &rect ) )
  576.                         this->TrackCell( where, cell );
  577.                     else
  578.                     {
  579.                         this->GetWiglyRect( cell, rect );
  580.                         if (    this->CanDrawHierarchy( cell ) &&
  581.                                 this->IsCellHeader( cell ) &&
  582.                                 ::PtInRect( where.whereLocal, &rect ) )
  583.                         {
  584.                             this->TrackWigly( where, cell );
  585.                         }
  586.                         else
  587.                         {
  588.                             if ( fAllowsRectSelection )
  589.                                 this->TrackSpace( where, cell );
  590.                         }
  591.                     }
  592.                 }
  593.             }
  594.             handled = TRUE;
  595.         }
  596.         break;
  597.  
  598.         case NO_COLUMN:
  599.         {
  600.             if ( fAllowsRectSelection )
  601.                 this->TrackSpace( where, cell );
  602.             else if ( cell != NO_CELL )
  603.                 this->SelectItem( where.macEvent, cell, TRUE );
  604.             handled = TRUE;
  605.         }
  606.         break;
  607.         
  608.         default:
  609.         break;
  610.     }
  611.     return handled;
  612. }
  613.  
  614. void LFinderView::SortByColumnNumber( UInt16 /*column*/, Boolean /*switchOrder*/ )
  615. {
  616. }
  617.  
  618. // Complex -- click on wigly, just track this click
  619. void LFinderView::ClickSelf( const SMouseDownEvent& where )
  620. {
  621.     SPoint32        whereImage;
  622.     Int16            column;
  623.     Boolean            inBar;
  624.     UInt32            cell;
  625.     
  626.     LocalToImagePoint( where.whereLocal, whereImage );
  627.  
  628.     cell = this->FetchCellAt( whereImage );
  629.     column = this->GetClickKind( where, cell, inBar );
  630.  
  631.     if ( inBar )
  632.     {
  633.         this->TrackResizeColumn( where, cell, column );
  634.     }
  635.     else
  636.     {
  637.         if ( this->DispatchClick( where, cell, column ) && GetClickCount() < 2 )
  638.         {
  639.             // We only switch the target if it's not a double-click. Otherwise,
  640.             // the double-click dispatch may have caused a target change and
  641.             // we would not want to undo that.
  642.             this->SwitchTarget( this );
  643.         }
  644.     }
  645. }
  646.  
  647. void LFinderView::DoResizeColumn( Int16 column, Int16 delta, Boolean inRefresh )
  648. {
  649.     for ( long i = column + 1; i < fNumberColumns; i++ )
  650.         fColumnOffsets[ i ] += delta;
  651.  
  652.     if ( inRefresh && fHeader )
  653.     {
  654.         if ( fHeader )
  655.             fHeader->Refresh();
  656.         this->Refresh();
  657.     }
  658. }
  659.  
  660. void LFinderView::TrackResizeColumn( const SMouseDownEvent& where, UInt32 cell, Int16 column )
  661. {
  662.     Rect            columnRect;
  663.     Rect            viewRect;
  664.     RgnHandle        myRgn;
  665.     Int16            delta;
  666.     Int32            result;
  667.  
  668.     if ( !this->FocusDraw() )
  669.         return;
  670.     
  671.     this->GetColumnRect( cell, column, columnRect );
  672.     this->CalcLocalFrameRect( viewRect );
  673.     
  674.     columnRect.left = columnRect.right - 1;
  675.     columnRect.right = columnRect.right + 1;
  676.     if ( fHeader )
  677.     {
  678.         SDimension16        size;
  679.         fHeader->GetFrameSize( size );
  680.         columnRect.top -= size.height;
  681.         viewRect.top -= size.height;
  682.     }
  683.     columnRect.top = viewRect.top--;
  684.     columnRect.bottom = viewRect.bottom++;
  685.     myRgn = ::NewRgn();
  686.     ::RectRgn( myRgn, &columnRect );
  687.     
  688.     viewRect.left = fColumnOffsets[ column ];
  689.     if ( viewRect.left < 1 )
  690.         viewRect.left = 1;
  691.     viewRect.right -= 1;
  692.  
  693.     result = ::DragGrayRgn(    myRgn, where.whereLocal, 
  694.                 &viewRect, &viewRect, hAxisOnly, NULL );        
  695.  
  696.     ::DisposeRgn( myRgn );
  697.  
  698.     delta = LoWord( result );
  699.     if ( ( result == kOutsideSlop ) || ( delta == 0 ) ) 
  700.         return;
  701.  
  702.     this->DoResizeColumn( column, delta, TRUE );
  703. }
  704.  
  705. UInt32 LFinderView::FetchCellAt( SPoint32& imagePt )
  706. {
  707.     UInt32        cell = NO_CELL;
  708.     
  709.     cell = ( imagePt.v / fCellHeight ) + 1;
  710.     if ( this->GetVisibleCount() < cell )
  711.         cell = this->GetVisibleCount();
  712.     return cell;
  713. }
  714.  
  715. void LFinderView::GetVisibleCells( UInt32& top, UInt32& bottom )
  716. {
  717.     SPoint32        loc;
  718.     
  719.     loc.v = mFrameLocation.v - mImageLocation.v;
  720.     loc.h = mFrameLocation.h - mImageLocation.h;
  721.     
  722.     top = this->FetchCellAt( loc );
  723.     
  724.     loc.v += ( mFrameSize.height - 1 );
  725.     loc.h += ( mFrameSize.width - 1 );
  726.     
  727.     bottom = this->FetchCellAt( loc );    
  728. }
  729.  
  730. void LFinderView::RevealCell( UInt32 cell )
  731. {
  732.     XP_ASSERT( cell );
  733.  
  734.     if ( this->FocusDraw() )
  735.     {
  736.         SPoint32        pt;
  737.         Point            localPt;
  738.         Rect            frame;
  739.         
  740.         pt.h = 0;
  741.         pt.v = ( cell - 1 ) * fCellHeight;
  742.         this->CalcLocalFrameRect( frame );
  743.         this->ImageToLocalPoint( pt, localPt );
  744.  
  745.         if ( localPt.v < frame.top )
  746.             this->ScrollImageTo( 0, pt.v, TRUE );
  747.         
  748.         if ( ( localPt.v + fCellHeight ) > ( frame.bottom - 1 ) )
  749.             this->ScrollImageTo( 0, ( pt.v + fCellHeight ) - mFrameSize.height + 1, TRUE );
  750.     }
  751. }
  752.  
  753. void LFinderView::GetColumnTitle( UInt16 column, CStr255& title )
  754. {
  755.     ::GetIndString( title, mUserCon, fColumnIDs[ column ] + 1 );
  756. }
  757.  
  758. void LFinderView::SetForeColor( const RGBColor& fore )
  759. {
  760.     fForeColor = fore;
  761. }
  762.  
  763. void LFinderView::SetBackColor( const RGBColor& back )
  764. {
  765.     fBackColor = back;
  766. }
  767.  
  768. Boolean LFinderView::FocusDraw(LPane* /*inSubPane*/)
  769. {
  770.     Boolean        focus;
  771.     
  772.     focus = LView::FocusDraw();
  773.     if ( focus )
  774.     {
  775.         UGraphics::SetIfBkColor( fBackColor );
  776.         UGraphics::SetIfColor( fForeColor );
  777.     }
  778.  
  779.     return focus;
  780. }
  781.  
  782. Boolean LFinderView::TrackHeader( const SMouseDownEvent& /*where*/, UInt16 clickWhere )
  783. {
  784.     Boolean                hilited = FALSE;
  785.     Rect                whichRect;
  786.  
  787.     if ( !this->FocusDraw() )
  788.         return FALSE;
  789.         
  790.     this->GetColumnRect( 1, clickWhere, whichRect );
  791.     whichRect.top = 1;
  792.     whichRect.bottom = fCellHeight - 2;
  793.     
  794.     while ( ::Button() )
  795.     {
  796.         SystemTask();
  797.         FocusDraw();
  798.  
  799.         Point                mouse;
  800.         ::GetMouse( &mouse );
  801.         // Ñ╩idling
  802.         // Ñ user feedback
  803.         if ( PtInRect( mouse, &whichRect ) )
  804.         {
  805.             if ( !hilited )
  806.             {
  807.                 hilited = TRUE;
  808.                 HiliteRect( whichRect );
  809.             }
  810.         }
  811.         else
  812.         {
  813.             if ( hilited )
  814.             {
  815.                 hilited = FALSE;
  816.                 HiliteRect( whichRect );
  817.             }
  818.         }
  819.     }
  820.     
  821.     return hilited;    
  822. }
  823.  
  824.  
  825. void LFinderView::DrawCellAt( UInt32 cell )
  826. {
  827.     Rect        cellRect;
  828.     
  829.     this->GetCellRect( cell, cellRect );
  830.  
  831.     FocusDraw();
  832.     ::EraseRect( &cellRect );
  833.         
  834.     // Ñ╩do not draw if we are not visible
  835.     // conversion of local to image coordinates (see LocalToImagePoint)
  836.     if ( !ImageRectIntersectsFrame(    cellRect.left - mImageLocation.h - mPortOrigin.h,
  837.                                     cellRect.top - mImageLocation.v - mPortOrigin.v,
  838.                                     cellRect.right - mImageLocation.h - mPortOrigin.h,
  839.                                     cellRect.bottom - mImageLocation.v - mPortOrigin.v ) )
  840.         return;
  841.  
  842.     for ( long i = 0; i < fNumberColumns; i++ )
  843.         this->DrawCellColumn( cell, i );
  844.         
  845.     this->HighlightCell( cell );
  846. }
  847.  
  848. void LFinderView::PutOnDuty(LCommander* inNewTarget)
  849. {
  850.     LCommander::PutOnDuty(inNewTarget);
  851.     RefreshSelectedCells();
  852. }
  853.  
  854. void LFinderView::TakeOffDuty()
  855. {
  856.     LCommander::TakeOffDuty();
  857.     RefreshSelectedCells();
  858. }
  859.  
  860. void LFinderView::GetWiglyRect( UInt32 cell, Rect& where )
  861. {
  862.     where.bottom = ( cell * fCellHeight ) + mPortOrigin.v + mImageLocation.v + 1;
  863.     where.top = where.bottom - ICON_HEIGHT;
  864.     where.left = WIGLY_LEFT_OFFSET + mPortOrigin.h + mImageLocation.h;
  865.     where.right = where.left + ICON_WIDTH;
  866. }
  867.  
  868. void LFinderView::GetIconRect( UInt32 cell, Rect& where )
  869. {
  870.     where.top = ( ( cell - 1 ) * fCellHeight ) + mPortOrigin.v + mImageLocation.v;
  871.     where.bottom = where.top + ICON_HEIGHT;
  872.     where.left = ( this->CellIndentLevel( cell ) * LEVEL_OFFSET ) +
  873.         WIGLY_LEFT_OFFSET + ICON_WIDTH +
  874.         mPortOrigin.h + mImageLocation.h;
  875.     where.right = where.left + ICON_WIDTH;
  876. }
  877.  
  878. void LFinderView::GetTextRect( UInt32 cell, Rect& where )
  879. {
  880.     where.top = ( ( cell - 1 ) * fCellHeight ) +
  881.         mPortOrigin.v + mImageLocation.v;
  882.     where.bottom = where.top + fCellHeight;
  883.     where.left = ( this->CellIndentLevel( cell ) * LEVEL_OFFSET ) + 
  884.         mPortOrigin.h + mImageLocation.h +
  885.         WIGLY_LEFT_OFFSET + (2 * ICON_WIDTH);
  886.         
  887.     CStr255        text;
  888.     this->CellText( cell, text );
  889.     long width = ::StringWidth( text );
  890.     if ( width )
  891.         where.right = where.left + width + 2;
  892.     else
  893.         where.right = where.left;
  894. }
  895.  
  896. void LFinderView::DrawIcon( Handle iconSuite, Boolean selected, const Rect& where )
  897. {
  898.     OSErr        err;
  899.     
  900.     if ( !iconSuite )
  901.         return;
  902.     
  903.     if ( !selected )
  904.         err = ::PlotIconSuite( &where, atHorizontalCenter | atVerticalCenter,
  905.                     ttNone, iconSuite );
  906.     else
  907.         err = ::PlotIconSuite( &where, atHorizontalCenter | atVerticalCenter,
  908.                     ttSelected, iconSuite );
  909. }
  910.  
  911. void LFinderView::DrawText( const Style& style, const CStr255& text, const Rect& where,
  912.     const TruncCode& trunc )
  913. {
  914.     DrawText(style, text, where, trunc, fTextTraits, fBaseline );
  915. }
  916.  
  917. void LFinderView::DrawText( const Style& style, const CStr255& text, const Rect& where,
  918.     const TruncCode& trunc, ResIDT inTextTraits, Int16 baseline )
  919. {
  920.     UTextTraits::SetPortTextTraits( inTextTraits );
  921.     
  922.     CStr255    texta = text;
  923.  
  924.     ::TextFace( style );
  925.     ::MoveTo( where.left + 2, where.top + baseline - 2 );
  926.     
  927.     if ( where.right >= ( where.left + 2 ) )
  928.     {
  929.         SInt16    width;
  930.         
  931.         width = where.right - where.left - 2;
  932.         
  933.         if ( trunc != CUSTOM_MIDDLE_TRUNCATION )
  934.             ::TruncString( width, texta, trunc );
  935.         else
  936.             MiddleTruncationThatWorks( texta, width );
  937.         
  938.         ::DrawString( texta );
  939.     }
  940. }
  941.  
  942. Boolean LFinderView::CanDrawHierarchy( UInt32 /*cell*/ )
  943. {
  944.     return TRUE;
  945. }
  946.  
  947. void LFinderView::DrawHierarchy( UInt32 cell )
  948. {
  949.     Handle        iconSuite = NULL;
  950.     Rect        where;
  951.     CStr255        text;
  952.     TruncCode    trunc;
  953.     Style        textStyle;
  954.     
  955.     this->CellText( cell, text );
  956.     
  957.     // Ñ╩plot the wigly
  958.     if ( this->IsCellHeader( cell ) )
  959.     {
  960.         this->GetWiglyRect( cell, where );
  961.         
  962.         if ( this->IsHeaderFolded( cell ) )
  963.             iconSuite = CIconList::GetIconSuite( WIGLY_CLOSED_ICON );
  964.         else
  965.             iconSuite = CIconList::GetIconSuite( WIGLY_OPEN_ICON );
  966.         this->DrawIcon( iconSuite, FALSE, where );
  967.     }
  968.  
  969.     // Ñ plot icon
  970.     if ( this->CellIcon( cell ) != 0 )
  971.     {
  972.         this->GetIconRect( cell, where );
  973.         
  974.         iconSuite = CIconList::GetIconSuite( this->CellIcon( cell ) );
  975.         this->DrawIcon( iconSuite,
  976.             ( this->IsCellSelected( cell ) && ( mActive == triState_On ) ),
  977.             where );
  978.     }
  979.  
  980.     // Ñ plot text
  981.     textStyle = CellTextStyle( cell );
  982.     ::TextFace( textStyle );
  983.  
  984.     this->GetTextRect( cell, where );
  985.     trunc = this->ColumnTruncationStyle( 0 );
  986.     this->DrawText( this->CellTextStyle( cell ) , text, where, trunc );
  987. }
  988.  
  989. void LFinderView::DrawCellColumn( UInt32 /*cell*/, UInt16 /*column*/ )
  990. {
  991. }
  992.  
  993. void LFinderView::HighlightCell( UInt32 cell )
  994. {
  995.     Rect        where;
  996.     
  997.     if ( fHighlightRow )
  998.         this->GetCellRect( cell, where );
  999.     else
  1000.     {
  1001.         this->GetTextRect( cell, where );
  1002.         where.top += 2;
  1003.         where.bottom -= 2;
  1004.     }
  1005.     
  1006.     // Ñ╩do the highlighting
  1007.     if ( this->IsCellSelected( cell ) )
  1008.     {
  1009.         if ( mActive == triState_On && this->IsOnDuty() )
  1010.         {
  1011.             LMSetHiliteMode( 0 );
  1012.             ::InvertRect( &where );
  1013.         }
  1014.         else
  1015.         {
  1016.             RGBColor        hiliteColor;
  1017.  
  1018.             ::PenPat( &qd.black );
  1019.             LMGetHiliteRGB( &hiliteColor );    /* don't put two ':' in front of this line */
  1020.             UGraphics::SetIfColor( hiliteColor );
  1021.             ::FrameRect( &where );
  1022.         }
  1023.     }
  1024. }
  1025.  
  1026. Int16 LFinderView::InResizableColumnBar( const Point where )
  1027. {
  1028.     long        inColumnBar = NO_COLUMN;
  1029.     Int16        h = where.h;
  1030.  
  1031.     for ( long i = 0; i < ( fNumberColumns - 1 ); i++ )
  1032.     {
  1033.         Int16        offset;
  1034.  
  1035.         offset = fColumnOffsets[ i + 1 ];
  1036.                 
  1037.         if ( ( h > ( offset - 2 ) ) && ( h < ( offset + 2 ) ) )
  1038.         {
  1039.             inColumnBar = i;
  1040.             break;
  1041.         }
  1042.     }
  1043.  
  1044.     return inColumnBar;
  1045. }
  1046.  
  1047. Int16 LFinderView::InColumn( const Point point )
  1048. {
  1049.     for ( long i = 0; i < fNumberColumns; i++ )
  1050.     {
  1051.         Rect        tmp;
  1052.         this->GetColumnRect( 1, i, tmp );
  1053.         if ( point.h >= tmp.left && point.h < tmp.right )
  1054.             return i;
  1055.     }
  1056.     return NO_COLUMN;
  1057. }
  1058.     
  1059. // the coordinates returned are in Local coordinates
  1060. Int16 LFinderView::GetClickKind( const SMouseDownEvent& where, UInt32 /*cell*/, 
  1061.     Boolean& inBar )
  1062. {
  1063.     Int16    i;
  1064.     
  1065.     i = this->InResizableColumnBar( where.whereLocal );
  1066.  
  1067.     if ( i != NO_COLUMN )
  1068.     {
  1069.         inBar = TRUE;
  1070.         return i;
  1071.     }
  1072.  
  1073.     inBar = FALSE;
  1074.     i = this->InColumn( where.whereLocal );
  1075.     return i;
  1076. }
  1077.  
  1078. void LFinderView::GetCellRect( UInt32 cell, Rect& r )
  1079. {
  1080.     Int32        localV;
  1081.     Int32        localH;
  1082.     
  1083.     localV = mPortOrigin.v + mImageLocation.v;
  1084.     localH = mPortOrigin.h + mImageLocation.h;
  1085.         
  1086.     // Ñ enclosing rectangle
  1087.     r.bottom = cell * fCellHeight + localV;
  1088.     r.top = r.bottom - fCellHeight;
  1089.     r.left = localH;
  1090.     r.right = mImageSize.width + localH;
  1091. }
  1092.  
  1093.  
  1094. void LFinderView::GetColumnRect( UInt32 cell, UInt16 column, Rect& r )
  1095. {
  1096.     Int32        localV;
  1097.     Int32        localH;
  1098.     
  1099.     localV = mPortOrigin.v + mImageLocation.v;
  1100.     localH = mPortOrigin.h + mImageLocation.h;
  1101.         
  1102.     r.bottom = cell * fCellHeight + localV; 
  1103.     r.top = r.bottom - fCellHeight;
  1104.     r.left = fColumnOffsets[ column ] + localH;
  1105.     if ( column >= ( fNumberColumns - 1 ) )
  1106.         r.right = mImageSize.width + localH;
  1107.     else
  1108.         r.right = fColumnOffsets[ column + 1 ] + localH;
  1109.  
  1110.     if ( r.right < r.left )
  1111.         r.right = mImageSize.width + localH;
  1112. }
  1113.  
  1114.             
  1115. // Ñ╩tracks movement inside little finder triangle
  1116. void LFinderView::TrackWigly( const SMouseDownEvent& where, UInt32 cell )
  1117. {
  1118.     Boolean                hilited = FALSE;
  1119.     Point                mouse;
  1120.     Rect                r;
  1121.     Handle                iconSuite = NULL;
  1122.     
  1123.     this->GetWiglyRect( cell, r );
  1124.  
  1125.     if ( this->IsHeaderFolded( cell ) )
  1126.         iconSuite = CIconList::GetIconSuite( WIGLY_CLOSED_ICON );
  1127.     else
  1128.         iconSuite = CIconList::GetIconSuite( WIGLY_OPEN_ICON );
  1129.     
  1130.     while ( ::Button() )
  1131.     {
  1132.         // Ñ╩idling
  1133.         SystemTask();
  1134.         FocusDraw();
  1135.  
  1136.         ::GetMouse( &mouse );
  1137.         // Ñ user feedback
  1138.         if ( PtInRect( mouse, &r ) )
  1139.         {
  1140.             if ( !hilited )
  1141.             {
  1142.                 hilited = TRUE;
  1143.                 this->DrawIcon( iconSuite, TRUE, r );
  1144.             }
  1145.         }
  1146.         else
  1147.         {
  1148.             if ( hilited )
  1149.             {
  1150.                 hilited = FALSE;
  1151.                 this->DrawIcon( iconSuite, FALSE, r );
  1152.             }
  1153.         }
  1154.     }
  1155.  
  1156.     FocusDraw();
  1157.  
  1158.     if ( hilited )
  1159.     {
  1160.         iconSuite = CIconList::GetIconSuite( WIGLY_INBETWEEN_ICON );
  1161.         if ( this->IsHeaderFolded( cell ) )    // Open to closed transition
  1162.         {
  1163.             iconSuite = CIconList::GetIconSuite( WIGLY_OPEN_ICON );
  1164.  
  1165.             // Ñ need to erase the rect, because icons draw masked
  1166.             ::EraseRect( &r );
  1167.             this->DrawIcon( iconSuite, FALSE, r );
  1168.  
  1169.             this->FoldHeader( cell, FALSE, TRUE, (where.macEvent.modifiers & optionKey) != 0 );
  1170.         }
  1171.         else
  1172.         {
  1173.             iconSuite = CIconList::GetIconSuite( WIGLY_CLOSED_ICON );
  1174.  
  1175.             // Ñ need to erase the rect, because icons draw masked
  1176.             ::EraseRect( &r );
  1177.             this->DrawIcon( iconSuite, FALSE, r );
  1178.  
  1179.             this->FoldHeader( cell, TRUE, TRUE, (where.macEvent.modifiers & optionKey) != 0 );
  1180.         }
  1181.     }
  1182. }
  1183.  
  1184. Boolean LFinderView::TrackMark( UInt16 track, const SMouseDownEvent& /*where*/, UInt32 cell,
  1185.     UInt16 drawIconID, UInt16 notDrawIconID )
  1186. {
  1187.     Boolean                hilited = FALSE;
  1188.     Rect                whichRect;
  1189.     Handle                drawIcon = NULL;
  1190.     Handle                notDrawIcon = NULL;
  1191.     Boolean                selected = FALSE;
  1192.     RGBColor            backColor;
  1193.         
  1194.     if ( !this->FocusDraw() )
  1195.         return FALSE;
  1196.         
  1197.     this->GetColumnRect( cell, track, whichRect );
  1198.     
  1199.     drawIcon = CIconList::GetIconSuite( drawIconID );
  1200.     notDrawIcon = CIconList::GetIconSuite( notDrawIconID );
  1201.     
  1202.     if ( !drawIcon || !notDrawIcon )
  1203.         return FALSE;
  1204.     
  1205.     whichRect.left += 2;
  1206.     whichRect.right = whichRect.left + ICON_WIDTH;
  1207.     whichRect.bottom = whichRect.top + ICON_HEIGHT;
  1208.     
  1209.     selected = this->IsCellSelected( cell );
  1210.     if ( selected )
  1211.         LMGetHiliteRGB( &backColor );
  1212.     else
  1213.         backColor = CPrefs::GetColor( CPrefs::White );
  1214.     
  1215.     while ( ::Button() )
  1216.     {
  1217.         // Ñ╩idling
  1218.         SystemTask();
  1219.         FocusDraw();
  1220.  
  1221.         Point                mouse;
  1222.         ::GetMouse( &mouse );
  1223.         // Ñ user feedback
  1224.         if ( PtInRect( mouse, &whichRect ) )
  1225.         {
  1226.             if ( !hilited )
  1227.             {
  1228.                 hilited = TRUE;
  1229.                 ::RGBBackColor( &backColor );            
  1230.                 ::EraseRect( &whichRect );
  1231.                 this->DrawIcon( drawIcon, FALSE, whichRect );
  1232.             }
  1233.         }
  1234.         else
  1235.         {
  1236.             if ( hilited )
  1237.             {
  1238.                 hilited = FALSE;
  1239.                 ::RGBBackColor( &backColor );
  1240.                 ::EraseRect( &whichRect );
  1241.                 this->DrawIcon( notDrawIcon, FALSE, whichRect );
  1242.             }
  1243.         }
  1244.     }
  1245.     
  1246.     return hilited;    
  1247. }
  1248.  
  1249. void LFinderView::TrackCell( const SMouseDownEvent &where, UInt32 cell )
  1250. {
  1251.     if ( !this->FocusDraw() )
  1252.         return;
  1253.         
  1254.     if ( GetClickCount() < 2 )
  1255.     {
  1256.         this->SelectItem( where.macEvent, cell, TRUE );
  1257.  
  1258.         // Ñ╩tricky: select the cell right away
  1259.         if (    this->IsCellSelected( cell ) && 
  1260.                 LDragAndDrop::DragAndDropIsPresent() && 
  1261.                 ::WaitMouseMoved( where.macEvent.where ) )
  1262.         {
  1263.             // Ñ reset the drag location
  1264.             fDragTarget.where = DRAG_NONE;
  1265.             this->MakeDragTask( where );
  1266.         }
  1267.     }
  1268.     else
  1269.         this->DoDoubleClick( cell, where.macEvent );
  1270. }
  1271.  
  1272. void LFinderView::DoDoubleClick( UInt32 cell, const EventRecord &/*event*/)
  1273. {
  1274.     if ( this->IsCellHeader( cell ) )
  1275.     {
  1276.         Boolean        folded = this->IsHeaderFolded( cell );
  1277.         this->FoldHeader( cell, !folded, TRUE, FALSE );
  1278.         RefreshCells( cell, cell, FALSE );
  1279.     }
  1280. }
  1281.  
  1282. void LFinderView::TrackSpace( const SMouseDownEvent& where, UInt32 /*cell*/ )
  1283. {
  1284.     Boolean        extend;
  1285.     Rect        antsRect;
  1286.     Rect        oldAntsRect;
  1287.     Point        start;
  1288.     Point        end;
  1289.     Point        current;
  1290.     SPoint32    tmpPt;
  1291.     EventRecord        tmp;
  1292.     
  1293.     UInt32        topCell;
  1294.     UInt32        botCell;
  1295.     
  1296.     extend = ( where.macEvent.modifiers & shiftKey ) != 0;
  1297.  
  1298.     if ( !extend )
  1299.         this->ClearSelection();
  1300.         
  1301.     start = where.whereLocal;
  1302.     end = start;
  1303.     antsRect = RectFromTwoPoints( start, end );
  1304.     
  1305.     tmp = where.macEvent;
  1306.     tmp.modifiers |= shiftKey;
  1307.      
  1308.     // Ñ draw ants
  1309.     DrawAntsRect( antsRect, patXor );    
  1310.     while ( ::Button() )
  1311.     {
  1312.         // Ñ╩idling
  1313.         SystemTask();
  1314.         FocusDraw();
  1315.         
  1316.         // Ñ╩ants always drawn when entering the loop. erase on exit
  1317.         ::GetMouse( ¤t );
  1318.         if ( ( current.v != end.v ) || ( current.h != end.h ) )
  1319.         {
  1320.             FocusDraw();
  1321.             // Ñ╩erase the ants
  1322.             DrawAntsRect( antsRect, patXor );    
  1323.             AutoScrollImage( current );
  1324.  
  1325.             end = current;
  1326.             oldAntsRect = antsRect;
  1327.             antsRect = RectFromTwoPoints( start, end );
  1328.  
  1329.             this->LocalToImagePoint( topLeft( oldAntsRect ), tmpPt );
  1330.             topCell = this->FetchCellAt( tmpPt );
  1331.             this->LocalToImagePoint( botRight( oldAntsRect ), tmpPt );
  1332.             botCell = this->FetchCellAt( tmpPt );
  1333.             
  1334.             this->LocalToImagePoint( topLeft( antsRect ), tmpPt );
  1335.             topCell = MIN( topCell, this->FetchCellAt( tmpPt ) );
  1336.             this->LocalToImagePoint( botRight( antsRect ), tmpPt );
  1337.             botCell = MAX( botCell, this->FetchCellAt( tmpPt ) );
  1338.             
  1339.             for ( UInt32 i = topCell; i <= botCell; i++ )
  1340.             {
  1341.                 if ( SectCellRect( i, oldAntsRect ) != SectCellRect( i, antsRect ) )
  1342.                     this->SelectItem( tmp, i, TRUE );
  1343.             }
  1344.             FocusDraw();
  1345.             // Ñ╩draw ants
  1346.             DrawAntsRect( antsRect, patXor );
  1347.         }
  1348.     }
  1349.     // Ñ draw ants
  1350.     DrawAntsRect( antsRect, patXor );
  1351. }
  1352.  
  1353. // Ñ╩does the icon, or the text of the cell sect this rect?
  1354. Boolean LFinderView::SectCellRect( UInt32 cell, Rect r )
  1355. {
  1356.     Rect            iconRect;
  1357.     Rect            textRect;
  1358.     Rect            dummy;
  1359.  
  1360.     this->GetIconRect( cell, iconRect );
  1361.     this->GetTextRect( cell, textRect );
  1362.         
  1363.     return ( ::SectRect( &iconRect, &r, &dummy ) ||
  1364.              ::SectRect( &textRect, &r, &dummy ) );
  1365. }
  1366.  
  1367. void LFinderView::LocalToGlobalRect( Rect& r )
  1368. {
  1369.     Point        p1;
  1370.     Point        p2;
  1371.     
  1372.     p1.h = r.left; p1.v = r.top;
  1373.     p2.h = r.right; p2.v = r.bottom;
  1374.     
  1375.     LocalToPortPoint( p1 );
  1376.     LocalToPortPoint( p2 );
  1377.     PortToGlobalPoint( p1 );
  1378.     PortToGlobalPoint( p2 );
  1379.     
  1380.     r.left = p1.h;
  1381.     r.top = p1.v;
  1382.     r.right = p2.h;
  1383.     r.bottom = p2.v;
  1384. }
  1385.  
  1386.  
  1387. // User feedback on dragging
  1388. void LFinderView::InsideDropArea( DragReference /*inDragRef*/ )
  1389. {
  1390.     Point            mouse;
  1391.     SPoint32        imageMouse;
  1392.     DropLocation    newDropLoc;
  1393.     Rect            enclosingRect;
  1394.     UInt32            cell;
  1395.     Boolean            nearTop;
  1396.     Boolean            nearBottom;
  1397.         
  1398.     if ( !this->FocusDraw() )
  1399.         return;
  1400.         
  1401.     // Ñ find out where the mouse is
  1402.     ::GetMouse( &mouse );
  1403.  
  1404.     this->LocalToImagePoint( mouse, imageMouse );
  1405.     
  1406.     // Ñ╩get information about the cell
  1407.     cell = this->FetchCellAt( imageMouse );
  1408.     if ( cell > 0 && cell <= this->GetVisibleCount() )
  1409.     {
  1410.         newDropLoc.cell = cell;
  1411.         this->GetCellRect( newDropLoc.cell, enclosingRect );
  1412.         nearTop = imageMouse.v < ( ( cell - 1 ) * fCellHeight + 2 );
  1413.          nearBottom = imageMouse.v > ( cell * fCellHeight + 2 );
  1414.  
  1415.         // Ñ cannot drag onto a selected cell?
  1416.         if ( this->IsCellSelected( newDropLoc.cell ) )
  1417.             newDropLoc.where = DRAG_NONE;
  1418.         else if ( this->IsCellHeader( newDropLoc.cell ) )    // Header 
  1419.         {
  1420.             if ( nearTop )                // Near the top of the header
  1421.             {
  1422.                 newDropLoc.cell -= 1;
  1423.                 newDropLoc.where = DRAG_AFTER;
  1424.             }
  1425.             else if ( nearBottom )        // Near the bottom of the header
  1426.             {
  1427.                 newDropLoc.where = DRAG_AFTER;                
  1428.             }
  1429.             else                        // Over the icon
  1430.                 newDropLoc.where = DRAG_INSIDE;
  1431.         }
  1432.         else                            // We are over a cell, the boundary is the half of the cell
  1433.             if (imageMouse.v < ((cell * fCellHeight) - (fCellHeight / 2)))
  1434.             {
  1435.                 newDropLoc.cell -= 1;
  1436.                 newDropLoc.where = DRAG_AFTER;
  1437.             }
  1438.             else
  1439.                 newDropLoc.where = DRAG_AFTER;
  1440.     
  1441.         if (    ( newDropLoc.cell == fDragTarget.cell ) && 
  1442.                 ( newDropLoc.where == fDragTarget.where ) )
  1443.             return;
  1444.     
  1445.         HighlightDropLocation( FALSE );
  1446.         fDragTarget = newDropLoc;
  1447.         HighlightDropLocation( TRUE );
  1448.     }
  1449.     XP_TRACE(("cell: %d, where: %d\n", fDragTarget.cell, fDragTarget.where ));
  1450. }
  1451.  
  1452. void LFinderView::LeaveDropArea( DragReference inDragRef )
  1453. {
  1454.     LDragAndDrop::LeaveDropArea( inDragRef );
  1455.     HighlightDropLocation( FALSE );
  1456.  
  1457.     fDragTarget.cell = 0;
  1458.     fDragTarget.where = DRAG_NONE;
  1459.     
  1460.     
  1461.     Point mouse;
  1462.     Rect  frame;
  1463.     
  1464.     FocusDraw();
  1465.     ::GetMouse(&mouse);
  1466.     CalcLocalFrameRect(frame);
  1467.     
  1468.     // yippee
  1469.     fDragLeaveDirection.top = fDragLeaveDirection.left = 
  1470.     fDragLeaveDirection.bottom = fDragLeaveDirection.right = false;
  1471.     
  1472.     
  1473.     // Remember which way the cursor left us, because those are the only directions
  1474.     // we'll allow autoscrolling until we are reentered.
  1475.     
  1476.     if ( ! (fDragLeaveDirection.left = (mouse.h < frame.left)))
  1477.         fDragLeaveDirection.right = (mouse.h > frame.right);
  1478.         
  1479.     if ( ! (fDragLeaveDirection.top = (mouse.v < frame.top)))
  1480.         fDragLeaveDirection.bottom = (mouse.v > frame.bottom);
  1481.  
  1482. }
  1483.  
  1484. // TRUE to show highlight, FALSE to hide
  1485. void LFinderView::HighlightDropLocation( Boolean show )
  1486. {
  1487.     Rect            textRect;
  1488.     Rect            iconRect;
  1489.     Handle            iconSuite;
  1490.     
  1491.     if ( !this->FocusDraw() )
  1492.         return;
  1493.         
  1494.     if ( fDragTarget.where == DRAG_NONE )
  1495.         return;
  1496.  
  1497.     if ( this->IsCellSelected( fDragTarget.cell ) && show )
  1498.         return;
  1499.         
  1500.     this->GetTextRect( fDragTarget.cell, textRect );
  1501.     this->GetIconRect( fDragTarget.cell, iconRect );
  1502.     
  1503.     switch ( fDragTarget.where )
  1504.     {
  1505.         case DRAG_NONE:
  1506.         break;
  1507.         
  1508.         case DRAG_INSIDE:
  1509.             iconSuite = CIconList::GetIconSuite( this->CellIcon( fDragTarget.cell ) );
  1510.             this->DrawIcon( iconSuite, show, iconRect );
  1511.         break;
  1512.         
  1513.         case DRAG_AFTER:
  1514.             ::PenMode( patXor );
  1515.             ::PenPat( &qd.black );
  1516.             ::PenSize( 1, 2 );
  1517.             MoveTo( textRect.left + 1, textRect.bottom - 1 );
  1518.             LineTo( textRect.right - 1, textRect.bottom - 1 );
  1519.             ::PenSize( 1, 1 );
  1520.         break;
  1521.     }
  1522. }    
  1523.  
  1524.  
  1525. void LFinderView::AddFlavors( DragReference /*inDragRef*/ )
  1526. {
  1527. }
  1528.  
  1529. // For each visible selected cell, add it to the drag rgn
  1530. void LFinderView::MakeDragRegion( DragReference /*inDragRef*/, RgnHandle dragRegion )
  1531. {
  1532.     UInt32            topCell;
  1533.     UInt32            bottomCell;
  1534.  
  1535.     GetVisibleCells( topCell, bottomCell );
  1536.  
  1537.     StRegion        tempOutRgn;
  1538.     StRegion        tempInRgn;
  1539.  
  1540.     for ( UInt32 cell = topCell; cell <= bottomCell; cell++ )
  1541.     {
  1542.         // Ñ for each selected cell, add the outline to the region
  1543.         if ( this->IsCellSelected( cell ) )    
  1544.         {
  1545.             Rect        iconRect;
  1546.             Rect        textRect;
  1547.             
  1548.             this->GetIconRect( cell, iconRect );
  1549.             this->GetTextRect( cell, textRect );
  1550.             
  1551.             InsetRect( &textRect, 1, 2 );
  1552.             
  1553.             // Ñ must translate local rect into global one
  1554.             LocalToGlobalRect( textRect );
  1555.             LocalToGlobalRect( iconRect );
  1556.             
  1557.             // Ñ add two rects
  1558.             RectRgn( tempOutRgn, &iconRect );
  1559.             RectRgn( tempInRgn, &iconRect );
  1560.             InsetRgn( tempInRgn, 1, 1 );
  1561.  
  1562.             DiffRgn( tempOutRgn, tempInRgn, tempInRgn );
  1563.             UnionRgn( tempInRgn, dragRegion, dragRegion );
  1564.  
  1565.             RectRgn( tempOutRgn, &textRect );    // text
  1566.             RectRgn( tempInRgn, &textRect );
  1567.  
  1568.             InsetRgn( tempInRgn, 1, 1 );
  1569.             DiffRgn( tempOutRgn, tempInRgn, tempInRgn );
  1570.             UnionRgn( tempInRgn, dragRegion, dragRegion );
  1571.         }
  1572.     }
  1573. }
  1574.  
  1575. Boolean LFinderView::ResizeTo( UInt32 newHeight, UInt32 newWidth )
  1576. {
  1577.     if ( newHeight != mImageSize.height || newWidth != mImageSize.width )
  1578.     {
  1579.         ResizeImageTo( newWidth, newHeight, TRUE );
  1580.         Rect        extraRect;    
  1581.         extraRect.bottom = mFrameSize.height;
  1582.         extraRect.right = mFrameSize.width;
  1583.         
  1584.         if ( ( newHeight < mFrameSize.height ) && FocusDraw() )
  1585.         {
  1586.             extraRect.top = newHeight;
  1587.             extraRect.left = 0;
  1588.             ::EraseRect( &extraRect );
  1589.             ::InvalRect( &extraRect );
  1590.         }
  1591.  
  1592.         if ( ( newWidth < mFrameSize.width ) && FocusDraw() )
  1593.         {
  1594.             extraRect.top = 0;
  1595.             extraRect.left = newWidth;
  1596.             ::EraseRect( &extraRect );
  1597.             ::InvalRect( &extraRect );
  1598.         }
  1599.         return TRUE;
  1600.     }
  1601.     else
  1602.         return FALSE;
  1603. }
  1604.  
  1605. void LFinderView::AdjustCursorSelf( Point inPortPt, const EventRecord& inMacEvent )
  1606. {
  1607.     Int16         i;
  1608.     PortToLocalPoint( inPortPt );
  1609.     i = this->InResizableColumnBar( inPortPt );
  1610.  
  1611.     if ( i != NO_COLUMN )
  1612.         ::SetCursor( *(::GetCursor( curs_HoriDrag ) ) );
  1613.     else
  1614.         LView::AdjustCursorSelf( inPortPt, inMacEvent );
  1615. }
  1616.  
  1617. /*******************************************************************************
  1618.  * LDragFinderView
  1619.  * Generic dragger for the Finder view
  1620.  *******************************************************************************/
  1621. LDragFinderTask::LDragFinderTask( const EventRecord& inEventRecord, LFinderView* view):
  1622.     LDragTask( inEventRecord )
  1623. {
  1624.     fView = view;
  1625.     
  1626.     fTrackerProc = NewDragTrackingHandlerProc(LDragFinderTask::ScrollingTracker);
  1627.     
  1628.     XP_ASSERT(fTrackerProc != NULL);
  1629.     
  1630.     if (fTrackerProc != NULL)
  1631.         (void) ::InstallTrackingHandler(fTrackerProc, fView->GetMacPort(), fView);
  1632. }
  1633.  
  1634. LDragFinderTask::~LDragFinderTask()
  1635. {
  1636.     if (fTrackerProc != NULL)
  1637.     {
  1638.         (void) ::RemoveTrackingHandler(fTrackerProc, fView->GetMacPort());
  1639.         DisposeRoutineDescriptor(fTrackerProc);
  1640.     }
  1641. }
  1642.  
  1643.  
  1644. void LDragFinderTask::MakeDragRegion( DragReference inDragRef, RgnHandle inDragRegion )
  1645. {
  1646.     if ( fView )
  1647.         fView->MakeDragRegion( inDragRef, inDragRegion );
  1648. }
  1649.  
  1650. void LDragFinderTask::AddFlavors( DragReference inDragRef )
  1651. {
  1652.     if ( fView )
  1653.         fView->AddFlavors( inDragRef );
  1654. }
  1655.  
  1656.  
  1657.  
  1658. pascal OSErr
  1659. LDragFinderTask::ScrollingTracker(    DragTrackingMessage     message, 
  1660.                                     WindowPtr                 /*theWindow*/, 
  1661.                                     void                 *    handlerRefCon, 
  1662.                                     DragReference             theDragRef        )
  1663. {                                    
  1664.     LFinderView *    view = (LFinderView *) handlerRefCon;
  1665.     
  1666.     if (message == kDragTrackingInWindow)
  1667.          view->DragScroll(theDragRef);
  1668.     
  1669.     return noErr;
  1670. }
  1671.  
  1672.  
  1673.     
  1674.  
  1675.  
  1676. void
  1677. MiddleTruncationThatWorks(    StringPtr    s,
  1678.                             SInt16        availableSpace    )
  1679. {                            
  1680. #if 1
  1681.     
  1682.     if (availableSpace > 40)
  1683.     {    
  1684.         ::TruncString( availableSpace, s, truncMiddle );
  1685.     }
  1686.     else
  1687.     {
  1688.         // OK, we're trying to ship 4.0 (like yesterday) but this middle truncation stuff
  1689.         // just doesn't work for international and local versions (problem with ellipsis
  1690.         // and problem with multi-byte characters)
  1691.         // Due to these problems and other problems that haven't yet been discovered in 4.0,
  1692.         // we decided to not allow any middle truncation (allows truncEnd)
  1693.  
  1694.         ::TruncString( availableSpace, s, truncEnd );
  1695.     }
  1696. #else
  1697.     Boolean        alreadyFit;
  1698.     SInt16        ellipsisWidth, width, halfSpace;
  1699.     UInt32        index, measureBytes;
  1700.     UInt8        length;
  1701.     unsigned char ellipsis;
  1702.     Handle        ellipsisHandle = NULL;    
  1703.     
  1704.     //
  1705.     // "Fast" case
  1706.     // 
  1707.     if ( ::StringWidth(s) <= availableSpace)
  1708.         return;        
  1709.         
  1710.     //
  1711.     // Get to know the ellipsis
  1712.     //
  1713.     // pkc (6/14/96) Hack for localization; use ellipsis character
  1714.     // loaded from resource.
  1715.     if( sTruncChar == 0 )
  1716.     {
  1717.         ellipsisHandle = ::GetResource('elps', 1000);
  1718.         if( ellipsisHandle )
  1719.         {
  1720.             // set sTruncChar and release resource
  1721.             sTruncChar = **ellipsisHandle;
  1722.             ::ReleaseResource(ellipsisHandle);
  1723.         }
  1724.         else
  1725.         {
  1726.             // What should we do if we can't load the resource?
  1727.             // For now, set to roman ellipsis because I'm lazy.
  1728.             sTruncChar = '╔';
  1729.         }
  1730.     }
  1731.     ellipsis = sTruncChar;
  1732.     ellipsisWidth = ::CharWidth(ellipsis);
  1733.     if (ellipsisWidth > availableSpace)
  1734.     {
  1735.         s[0] = 0;    // cheezy bailout
  1736.         return;
  1737.     }
  1738.     
  1739.     if (ellipsisWidth == availableSpace)
  1740.     {
  1741.         s[0] = 1;
  1742.         s[1] = ellipsis;
  1743.         return;
  1744.     }
  1745.     
  1746.     
  1747.     //
  1748.     // Find block of text that takes up half of the available space
  1749.     // on the left. (minus half the ellipsis)
  1750.     //
  1751.     
  1752.     halfSpace    = ((availableSpace >> 1) - (ellipsisWidth >> 1));
  1753.     index        = halfSpace/8 + 1;        // just a beginning guess
  1754.     
  1755.     alreadyFit    = false;                
  1756.     
  1757.     do
  1758.     {
  1759.         width = ::TextWidth((char*)s, 1, index);
  1760.         
  1761.         // Too wide ?, go narrow
  1762.         if (width > halfSpace)
  1763.         {
  1764.             index--;
  1765.             
  1766.             // If we fit with the step back, bail
  1767.             if (alreadyFit)
  1768.                 break;
  1769.         }
  1770.         else
  1771.         
  1772.         // Do we fit ? try wider
  1773.         if (width < halfSpace)
  1774.         {
  1775.             index++;
  1776.             alreadyFit = true;        // we'll try adding one more char, 
  1777.                                     // but if it fails, just bounce back 
  1778.                                     // to this case        
  1779.         }
  1780.         else
  1781.             break;
  1782.     
  1783.         if (index == 0)        
  1784.             break;                    // no room for any text on the left
  1785.             
  1786.         XP_ASSERT(index <= s[0]);
  1787.         
  1788.     } while (true);
  1789.     
  1790.     
  1791.     // jam in the ellipsis
  1792.     s[index+1] = ellipsis;
  1793.     length = index+1;
  1794.     
  1795.     //
  1796.     // if index is 0, we have no room for anything 
  1797.     // but the ellipsis, so bail
  1798.     //
  1799.     if (index == 0)    
  1800.     {
  1801.         s[0] = 1;
  1802.         return;
  1803.     }
  1804.     
  1805.     //
  1806.     // Now find text to fit to the right of the ellipsis
  1807.     //
  1808.     
  1809.     halfSpace         = availableSpace - (width + ellipsisWidth);
  1810.     index             = s[0] - (halfSpace/8);                        // another guess to begin
  1811.     measureBytes     = (s[0] - index) + 1;
  1812.     alreadyFit        = false;
  1813.     
  1814.     do
  1815.     {
  1816.         width = ::TextWidth((char*)s, index, measureBytes);
  1817.     
  1818.         // If we're too wide, take a step back.
  1819.         if (width > halfSpace)
  1820.         {
  1821.             index++;
  1822.             measureBytes--;
  1823.             
  1824.             //
  1825.             // if we already know that we fit 
  1826.             // with the step back, get out 
  1827.             //
  1828.             
  1829.             if (alreadyFit)    
  1830.                 break;
  1831.         }    
  1832.         
  1833.         // If we're too narrow, go wider
  1834.         else if (width < halfSpace)
  1835.         {
  1836.             index--;
  1837.             measureBytes++;
  1838.             alreadyFit = true;    // we'll try adding one more char, 
  1839.                                 // but if it fails, just bounce back 
  1840.                                 // to this case            
  1841.         }
  1842.         else
  1843.             break;
  1844.             
  1845.         
  1846.         if (index > s[0])
  1847.         {
  1848.             measureBytes = 0;    // no room for any text on the right
  1849.             break;
  1850.         }    
  1851.         
  1852.         XP_ASSERT(index > 0);
  1853.             
  1854.     } while (true);
  1855.     
  1856.     
  1857.     if (measureBytes != 0)
  1858.     {
  1859.         //
  1860.         // shift the right half of the text down to meet the ellipsis
  1861.         //
  1862.         ::BlockMoveData( &s[index], &s[length+1], measureBytes);
  1863.         
  1864.         length += measureBytes;
  1865.     }
  1866.     
  1867.     s[0] = length;
  1868.     
  1869.     XP_ASSERT( ::StringWidth(s) <= availableSpace );
  1870. #endif
  1871. }    
  1872.         
  1873. void MiddleTruncationThatWorks(char *s, Int16 &ioLength, Int16 availableSpace)
  1874. {                            
  1875. #if 1
  1876.     if (availableSpace > 40)
  1877.     {    
  1878.         ::TruncText( availableSpace, s, &ioLength, truncMiddle );
  1879.     }
  1880.     else
  1881.     {
  1882.     // OK, we're trying to ship 4.0 (like yesterday) but this middle truncation stuff
  1883.     // just doesn't work for international and local versions (problem with ellipsis
  1884.     // and problem with multi-byte characters)
  1885.     // Due to these problems and other problems that haven't yet been discovered in 4.0,
  1886.     // we decided to not allow any middle truncation (allows truncEnd)
  1887.  
  1888.         ::TruncText( availableSpace, s, &ioLength, truncEnd );
  1889.     }
  1890. #else
  1891.     Boolean        alreadyFit;
  1892.     SInt16        ellipsisWidth, width, halfSpace;
  1893.     UInt32        index, measureBytes;
  1894.     Int16        length = outLength;
  1895.     unsigned char ellipsis;
  1896.     Handle        ellipsisHandle = NULL;    
  1897.     
  1898.     //
  1899.     // "Fast" case
  1900.     // 
  1901.     if ( ::TextWidth(s, 0, length) <= availableSpace)
  1902.         return;        
  1903.         
  1904.     //
  1905.     // Get to know the ellipsis
  1906.     //
  1907.     // pkc (6/14/96) Hack for localization; use ellipsis character
  1908.     // loaded from resource.
  1909.     if( sTruncChar == 0 )
  1910.     {
  1911.         ellipsisHandle = ::GetResource('elps', 1000);
  1912.         if( ellipsisHandle )
  1913.         {
  1914.             // set sTruncChar and release resource
  1915.             sTruncChar = **ellipsisHandle;
  1916.             ::ReleaseResource(ellipsisHandle);
  1917.         }
  1918.         else
  1919.         {
  1920.             // What should we do if we can't load the resource?
  1921.             // For now, set to roman ellipsis because I'm lazy.
  1922.             sTruncChar = '╔';
  1923.         }
  1924.     }
  1925.     ellipsis = sTruncChar;
  1926.     ellipsisWidth = ::CharWidth(ellipsis);
  1927.     if (ellipsisWidth > availableSpace)
  1928.     {
  1929.         outLength = 0;    // cheezy bailout
  1930.         return;
  1931.     }
  1932.     
  1933.     if (ellipsisWidth == availableSpace)
  1934.     {
  1935.         outLength = 1;
  1936.         s[0] = ellipsis;
  1937.         return;
  1938.     }
  1939.     
  1940.     
  1941.     //
  1942.     // Find block of text that takes up half of the available space
  1943.     // on the left. (minus half the ellipsis)
  1944.     //
  1945.     
  1946.     halfSpace    = ((availableSpace >> 1) - (ellipsisWidth >> 1));
  1947.     index        = halfSpace/8 + 1;        // just a beginning guess
  1948.     
  1949.     alreadyFit    = false;                
  1950.     
  1951.     do
  1952.     {
  1953.         width = ::TextWidth(s, 0, index + 1);
  1954.         
  1955.         // Too wide ?, go narrow
  1956.         if (width > halfSpace)
  1957.         {
  1958.             index--;
  1959.             
  1960.             // If we fit with the step back, bail
  1961.             if (alreadyFit)
  1962.                 break;
  1963.         }
  1964.         else
  1965.         
  1966.         // Do we fit ? try wider
  1967.         if (width < halfSpace)
  1968.         {
  1969.             index++;
  1970.             alreadyFit = true;        // we'll try adding one more char, 
  1971.                                     // but if it fails, just bounce back 
  1972.                                     // to this case        
  1973.         }
  1974.         else
  1975.             break;
  1976.     
  1977.         if (index == -1)        
  1978.             break;                    // no room for any text on the left
  1979.         
  1980.         XP_ASSERT(index < outLength);
  1981.         
  1982.     } while (true);
  1983.     
  1984.     
  1985.     // jam in the ellipsis
  1986.     s[index+1] = ellipsis;
  1987.     length = index+1;
  1988.     
  1989.     //
  1990.     // if index is 0, we have no room for anything 
  1991.     // but the ellipsis, so bail
  1992.     //
  1993.     if (index == -1)    
  1994.     {
  1995.         outLength = 1;
  1996.         return;
  1997.     }
  1998.     
  1999.     //
  2000.     // Now find text to fit to the right of the ellipsis
  2001.     //
  2002.     halfSpace         = availableSpace - (width + ellipsisWidth);
  2003.     index             = outLength - (halfSpace/8);                        // another guess to begin
  2004.     measureBytes     = outLength - index + 1;
  2005.     alreadyFit        = false;
  2006.     
  2007.     do
  2008.     {
  2009.         width = ::TextWidth(s, index, measureBytes);
  2010.     
  2011.         // If we're too wide, take a step back.
  2012.         if (width > halfSpace)
  2013.         {
  2014.             index++;
  2015.             measureBytes--;
  2016.             
  2017.             //
  2018.             // if we already know that we fit 
  2019.             // with the step back, get out 
  2020.             //
  2021.             
  2022.             if (alreadyFit)    
  2023.                 break;
  2024.         }    
  2025.         
  2026.         // If we're too narrow, go wider
  2027.         else if (width < halfSpace)
  2028.         {
  2029.             index--;
  2030.             measureBytes++;
  2031.             alreadyFit = true;    // we'll try adding one more char, 
  2032.                                 // but if it fails, just bounce back 
  2033.                                 // to this case            
  2034.         }
  2035.         else
  2036.             break;
  2037.             
  2038.         
  2039.         if (index > outLength)
  2040.         {
  2041.             measureBytes = 0;    // no room for any text on the right
  2042.             break;
  2043.         }    
  2044.         
  2045.         XP_ASSERT(index > 0);
  2046.             
  2047.     } while (true);
  2048.     
  2049.     
  2050.     if (measureBytes != 0)
  2051.     {
  2052.         //
  2053.         // shift the right half of the text down to meet the ellipsis
  2054.         //
  2055.         ::BlockMoveData( &s[index], &s[length+1], measureBytes);
  2056.         
  2057.         length += measureBytes;
  2058.     }
  2059.     
  2060.     outLength = length;
  2061.     
  2062.     XP_ASSERT( ::TextWidth(s, 0, outLength) <= availableSpace );
  2063. #endif
  2064. }    
  2065.     
  2066.     
  2067.  
  2068.  
  2069.