home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / gui / CMouseDragger.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  27.8 KB  |  769 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.  
  20. /*====================================================================================*/
  21.     #pragma mark INCLUDE FILES
  22. /*====================================================================================*/
  23.  
  24. #include "CMouseDragger.h"
  25.  
  26.  
  27. /*====================================================================================*/
  28.     #pragma mark TYPEDEFS
  29. /*====================================================================================*/
  30.  
  31.  
  32. /*====================================================================================*/
  33.     #pragma mark CONSTANTS
  34. /*====================================================================================*/
  35.  
  36.  
  37. /*====================================================================================*/
  38.     #pragma mark INTERNAL CLASS DECLARATIONS
  39. /*====================================================================================*/
  40.  
  41.  
  42. /*====================================================================================*/
  43.     #pragma mark INTERNAL FUNCTION PROTOTYPES
  44. /*====================================================================================*/
  45.  
  46.  
  47. /*====================================================================================*/
  48.     #pragma mark CLASS IMPLEMENTATIONS
  49. /*====================================================================================*/
  50.  
  51. #pragma mark -
  52.  
  53. /*======================================================================================
  54.     Track the mouse within the view specified by inView. The beginning mouse tracking
  55.     point is given by inStartMouseImagePt, which is in the image coordinate system
  56.     of inView. The mouse movements are pinned to the rect specified by inMouseImagePinRect,
  57.     which again is in the image coordinate system of inView. If inMouseImagePinRect is
  58.     nil, the mouse is pinned to the current image size of the view. This method handles
  59.     all interaction with the user until the mouse button is let up. If inStartMouseImagePt
  60.     is not within inMouseImagePinRect, it is forced to be within the rect by this method.
  61.     The inMinHMoveStart and inMinVMoveStart values specify the minimum amount of movement
  62.     required in either the horizontal or vertical directions to begin mouse tracking.
  63.     
  64.     If the mouse moved from the original point specified by inStartMouseImagePt (as adjusted
  65.     to be within inMouseImagePinRect, if necessary), the method returns true; otherwise,
  66.     no mouse movement occurred and the method returns false.
  67.     
  68.     The methods BeginTracking(), KeepTracking(), and EndTracking() are meant to be 
  69.     overriden by subclasses to implement the behavior of the mouse movements. See these
  70.     method for descriptions.
  71. ======================================================================================*/
  72.  
  73. Boolean CMouseDragger::DoTrackMouse(LView *inView, const SPoint32 *inStartMouseImagePt,
  74.                                     const LImageRect *inMouseImagePinRect,
  75.                                     const Int16 inMinHMoveStart, const Int16 inMinVMoveStart) {
  76.  
  77.     mView = inView;
  78.     
  79.     // Setup tracking variables. In addtion to pinning the current mouse point to the specified
  80.     // image rect, we also pin it to the frame of the view.
  81.     
  82.     LImageRect imagePinRect;
  83.     LImageRect viewImageBounds;
  84.     LImageRect viewFrameImageBounds;
  85.     
  86.     {
  87.         SDimension32 imageSize;
  88.         inView->GetImageSize(imageSize);
  89.         viewImageBounds.Set(0, 0, imageSize.width, imageSize.height);    // Add one since pin-rect subtracts 1
  90.     }
  91.  
  92.     if ( inMouseImagePinRect ) {
  93.         imagePinRect.Set(inMouseImagePinRect);
  94.         if ( imagePinRect.Left() < viewImageBounds.Left() ) imagePinRect.Left(viewImageBounds.Left());
  95.         if ( imagePinRect.Top() < viewImageBounds.Top() ) imagePinRect.Top(viewImageBounds.Top());
  96.         if ( imagePinRect.Right() > viewImageBounds.Right() ) imagePinRect.Right(viewImageBounds.Right());
  97.         if ( imagePinRect.Bottom() > viewImageBounds.Bottom() ) imagePinRect.Bottom(viewImageBounds.Bottom());
  98.     } else {
  99.         imagePinRect.Set(&viewImageBounds);
  100.     }
  101.     
  102.     Rect viewGlobalFrame, viewPortFrame;
  103.     mView->CalcPortFrameRect(viewPortFrame);
  104.     viewGlobalFrame = viewPortFrame;
  105.     mView->PortToGlobalPoint(topLeft(viewGlobalFrame));
  106.     mView->PortToGlobalPoint(botRight(viewGlobalFrame));
  107.  
  108.     // Pin start point
  109.     
  110.     mStartImagePt = *inStartMouseImagePt;
  111.     imagePinRect.PinPoint(&mStartImagePt.h, &mStartImagePt.v);
  112.     PortToImageRect(mView, &viewPortFrame, &viewFrameImageBounds);
  113.     viewFrameImageBounds.PinPoint(&mStartImagePt.h, &mStartImagePt.v);
  114.     
  115.     mEndImagePt = mStartImagePt;
  116.     SPoint32 lastPoint = mStartImagePt;
  117.     
  118.     // Let subclasses do something when we start
  119.     
  120.     BeginTracking(&mStartImagePt);
  121.     
  122.     // Do the tracking
  123.     
  124.     Boolean trackingStarted = false, keepTracking = true;
  125.     EventRecord macEvent;
  126.     
  127.     Int32 nextScrollTime = 0;
  128.     
  129.     Try_ {
  130.         while ( keepTracking && ::WaitMouseUp() ) {
  131.         
  132.             // Give background processing time
  133.             ::WaitNextEvent(0, &macEvent, 0, nil);
  134.         
  135.             SPoint32 newImagePoint;
  136.             GlobalToImagePt(mView, macEvent.where, &newImagePoint);
  137.  
  138.             Boolean didntScrollView = true;
  139.         
  140.             // Determine if we need to scroll the image, if so handle
  141.             // user tracking here
  142.             
  143.             if ( CanScrollView(mView, macEvent.where, &viewGlobalFrame) ) {
  144.             
  145.                 // Make sure that we don't scroll too quickly
  146.                 
  147.                 if ( nextScrollTime <= LMGetTicks() ) {
  148.                 
  149.                     // Need to scroll the view
  150.                     Point localPt = macEvent.where;
  151.                     mView->GlobalToPortPoint(localPt);
  152.                     mView->PortToLocalPoint(localPt);
  153.                     AboutToScrollView(&mStartImagePt, &mEndImagePt);
  154.                     
  155.                     mView->AutoScrollImage(localPt);    // Auto scroll the image
  156.                     didntScrollView = false;
  157.                     nextScrollTime = LMGetTicks() + 2;
  158.                     
  159.                     // Pin point
  160.  
  161.                     GlobalToImagePt(mView, macEvent.where, &newImagePoint);
  162.                     imagePinRect.PinPoint(&newImagePoint.h, &newImagePoint.v);
  163.                     PortToImageRect(mView, &viewPortFrame, &viewFrameImageBounds);
  164.                     viewFrameImageBounds.PinPoint(&newImagePoint.h, &newImagePoint.v);
  165.                     
  166.                     if ( !LImageRect::EqualPoints32(&newImagePoint, &mEndImagePt) ) {
  167.                         lastPoint = mEndImagePt;
  168.                         mEndImagePt = newImagePoint;
  169.                     }
  170.                     DoneScrollingView(&mStartImagePt, &mEndImagePt);
  171.                 }
  172.             }
  173.             
  174.             // If we didn't scroll the image, handle user tracking here
  175.             
  176.             if ( didntScrollView ) {
  177.                 imagePinRect.PinPoint(&newImagePoint.h, &newImagePoint.v);
  178.                 viewFrameImageBounds.PinPoint(&newImagePoint.h, &newImagePoint.v);
  179.                 if ( !LImageRect::EqualPoints32(&newImagePoint, &mEndImagePt) ) {
  180.                     if ( !trackingStarted ) {
  181.                         Int32 deltaH = newImagePoint.h - mStartImagePt.h;
  182.                         Int32 deltaV = newImagePoint.v - mStartImagePt.v;
  183.                         if ( deltaH < 0 ) deltaH = -deltaH;
  184.                         if ( deltaV < 0 ) deltaV = -deltaV;
  185.                         trackingStarted = ((deltaH >= inMinHMoveStart) || (deltaV >= inMinVMoveStart));
  186.                     }
  187.                     if ( trackingStarted ) {
  188.                         lastPoint = mEndImagePt;
  189.                         mEndImagePt = newImagePoint;
  190.                         
  191.                         keepTracking = KeepTracking(&mStartImagePt, &lastPoint, &mEndImagePt);
  192.                     }
  193.                 }
  194.             }
  195.         }
  196.  
  197.         EndTracking(&mStartImagePt, &mEndImagePt);
  198.     }
  199.     Catch_(inErr) {
  200.         // Always call EndTracking()
  201.         EndTracking(&mStartImagePt, &mEndImagePt);
  202.  
  203.         Throw_(inErr);
  204.     }
  205.     EndCatch_
  206.  
  207.     return !LImageRect::EqualPoints32(&mStartImagePt, &mEndImagePt);
  208. }
  209.  
  210.  
  211. /*======================================================================================
  212.     Return true if the global point inGlobalMousePt will cause a scroll of the view
  213.     inView. inGlobalViewFrame is the frame of the view in global coordinates or nil
  214.     if it has not been calculated yet.
  215. ======================================================================================*/
  216.  
  217. Boolean CMouseDragger::CanScrollView(LView *inView, Point inGlobalMousePt, const Rect *inGlobalViewFrame) {
  218.  
  219.     Rect viewGlobalFrame;
  220.     
  221.     if ( inGlobalViewFrame == nil ) {
  222.         // We calculate it here for caller!
  223.         inView->CalcPortFrameRect(viewGlobalFrame);
  224.         inView->PortToGlobalPoint(topLeft(viewGlobalFrame));
  225.         inView->PortToGlobalPoint(botRight(viewGlobalFrame));
  226.         inGlobalViewFrame = &viewGlobalFrame;
  227.     }
  228.  
  229.     Boolean    canScroll = false;
  230.     
  231.     SPoint32 scrollUnits;
  232.     inView->GetScrollUnit(scrollUnits);
  233.  
  234.     Int32 horizScroll = 0;
  235.     if ( inGlobalMousePt.h < inGlobalViewFrame->left ) {
  236.         horizScroll = -scrollUnits.h;
  237.     } else if ( inGlobalMousePt.h > inGlobalViewFrame->right ) {
  238.         horizScroll = scrollUnits.h;
  239.     }
  240.     
  241.     Int32 vertScroll = 0;
  242.     if ( inGlobalMousePt.v < inGlobalViewFrame->top ) {
  243.         vertScroll = -scrollUnits.v;
  244.     } else if (inGlobalMousePt.v > inGlobalViewFrame->bottom) {
  245.         vertScroll = scrollUnits.v;
  246.     }    
  247.     
  248.     if ( (horizScroll != 0) || (vertScroll != 0) ) {
  249.     
  250.         SPoint32 imageLocation;
  251.         inView->GetImageLocation(imageLocation);
  252.         SPoint32 frameLocation;
  253.         inView->GetFrameLocation(frameLocation);
  254.         SDimension32 imageSize;
  255.         inView->GetImageSize(imageSize);
  256.         SDimension16 frameSize;
  257.         inView->GetFrameSize(frameSize);
  258.  
  259.         if ( vertScroll != 0 ) {
  260.             Int32 tryDown = imageLocation.v - vertScroll;
  261.             if ( tryDown > frameLocation.v ) {
  262.                 if ( imageLocation.v <= frameLocation.v ) {
  263.                     vertScroll = imageLocation.v - frameLocation.v;
  264.                 } else if ( vertScroll < 0 ) {
  265.                     vertScroll = 0;
  266.                 }
  267.             } else if ( (tryDown + imageSize.height) < (frameLocation.v + frameSize.height)) {
  268.                 if ( (imageLocation.v + imageSize.height) >= (frameLocation.v + frameSize.height) ) {
  269.                     vertScroll = imageLocation.v - frameLocation.v + imageSize.height - frameSize.height;
  270.                 } else if ( vertScroll > 0 ) {
  271.                     vertScroll = 0;
  272.                 }
  273.             }
  274.         }
  275.         
  276.         if ( horizScroll != 0 ) {
  277.             Int32 tryLeft = imageLocation.h - horizScroll;
  278.             if ( tryLeft > frameLocation.h ) {
  279.                 if ( imageLocation.h <= frameLocation.h ) {
  280.                     horizScroll = imageLocation.h - frameLocation.h;
  281.                 } else if ( horizScroll < 0 ) {
  282.                     horizScroll = 0;
  283.                 }
  284.             } else if ( (tryLeft + imageSize.width) < (frameLocation.h + frameSize.width) ) {
  285.                 if ( (imageLocation.h + imageSize.width) >= (frameLocation.h + frameSize.width) ) {
  286.                     horizScroll = imageLocation.h - frameLocation.h + imageSize.width - frameSize.width;
  287.                 } else if (horizScroll > 0) {
  288.                     horizScroll = 0;
  289.                 }
  290.             }
  291.         }
  292.             
  293.         canScroll = (horizScroll != 0) || (vertScroll != 0);
  294.     }
  295.     
  296.     return canScroll;
  297. }
  298.  
  299.  
  300. /*======================================================================================
  301.     Convert the specified global point to the image coordinate system of inView.
  302. ======================================================================================*/
  303.  
  304. void CMouseDragger::GlobalToImagePt(LView *inView, Point inGlobalPt, SPoint32 *outImagePt) {
  305.  
  306.     inView->GlobalToPortPoint(inGlobalPt);
  307.     inView->PortToLocalPoint(inGlobalPt);
  308.     inView->LocalToImagePoint(inGlobalPt, *outImagePt);
  309. }
  310.  
  311.  
  312. /*======================================================================================
  313.     Convert the specified image point to the port coordinate system of inView.
  314. ======================================================================================*/
  315.  
  316. void CMouseDragger::ImageToPortPt(LView *inView, const SPoint32 *inImagePt, Point *outPortPt) {
  317.  
  318.     inView->ImageToLocalPoint(*inImagePt, *outPortPt);
  319.     inView->LocalToPortPoint(*outPortPt);
  320. }
  321.  
  322.  
  323. /*======================================================================================
  324.     Convert the specified port point to the image coordinate system of inView.
  325. ======================================================================================*/
  326.  
  327. void CMouseDragger::PortToImagePt(LView *inView, Point inPortPoint, SPoint32 *outImagePt) {
  328.  
  329.     inView->PortToLocalPoint(inPortPoint);
  330.     inView->LocalToImagePoint(inPortPoint, *outImagePt);
  331. }
  332.  
  333.  
  334. /*======================================================================================
  335.     Convert the specified port rect to the image coordinate system of inView.
  336. ======================================================================================*/
  337.  
  338. void CMouseDragger::PortToImageRect(LView *inView, const Rect *inPortRect, LImageRect *outImageRect) {
  339.  
  340.     PortToImagePt(inView, topLeft(*inPortRect), outImageRect->TopLeft());
  341.     PortToImagePt(inView, botRight(*inPortRect), outImageRect->BotRight());
  342. }
  343.  
  344.  
  345. /*======================================================================================
  346.     Convert the specified port rect to the image coordinate system of inView.
  347. ======================================================================================*/
  348.  
  349. void CMouseDragger::ImageToLocalRect(LView *inView, LImageRect *inImageRect, 
  350.                                      Rect *outLocalRect) {
  351.  
  352.     inView->ImageToLocalPoint(*inImageRect->TopLeft(), topLeft(*outLocalRect));
  353.     inView->ImageToLocalPoint(*inImageRect->BotRight(), botRight(*outLocalRect));
  354. }
  355.  
  356.  
  357. /*======================================================================================
  358.     This method is ALWAYS called from within the DoTrackMouse() method just before
  359.     the mouse tracking loop begins. If you want to setup instance varibles before
  360.     tracking begins, or draw an initial outline of a tracking image, this is the
  361.     place to do it. 
  362.     
  363.     The inStartMouseImagePt parameter has been pinned to the bounds passed to 
  364.     DoTrackMouse() in the inMouseImagePinRect parameter and is also pinned to the
  365.     frame of the view.
  366. ======================================================================================*/
  367.  
  368. void CMouseDragger::BeginTracking(const SPoint32 *inStartMouseImagePt) {
  369.  
  370.     // Draw
  371.     DrawDragRegion(inStartMouseImagePt, inStartMouseImagePt, eDoDraw);
  372. }
  373.  
  374.  
  375. /*======================================================================================
  376.     This method is called anytime the mouse moves to a new location within the
  377.     bounds passed to DoTrackMouse() in the inMouseImagePinRect parameter. The points
  378.     inPrevMouseImagePt and inCurrMouseImagePt will always be different. Note that
  379.     this method may NEVER be called if the user never moves the mouse from its 
  380.     initial position. This method should perform visual dragging of a region or
  381.     other user tracking interaction.
  382.     
  383.     If the method returns false, mouse tracking is stopped.
  384.     
  385.     All input points have been pinned to the bounds passed to DoTrackMouse() in the 
  386.     inMouseImagePinRect parameter and are also pinned to the frame of the view.
  387. ======================================================================================*/
  388.  
  389. Boolean CMouseDragger::KeepTracking(const SPoint32 *inStartMouseImagePt,
  390.                                    const SPoint32 *inPrevMouseImagePt,
  391.                                    const SPoint32 *inCurrMouseImagePt) {
  392.  
  393.     // Erase
  394.     DrawDragRegion(inStartMouseImagePt, inPrevMouseImagePt, eDoErase);
  395.  
  396.     // Draw
  397.     DrawDragRegion(inStartMouseImagePt, inCurrMouseImagePt, eDoDraw);
  398.  
  399.     return true;    // Continue tracking
  400. }
  401.  
  402.  
  403. /*======================================================================================
  404.     This method is ALWAYS called at the end of user mouse tracking. If the points
  405.     inStartMouseImagePt and inEndMouseImagePt not are equal, the user actually move 
  406.     the mouse somewhere different from where it started. This method should normally
  407.     erase any visual representation of a dragging region.
  408.  
  409.     All input points have been pinned to the bounds passed to DoTrackMouse() in the 
  410.     inMouseImagePinRect parameter and are also pinned to the frame of the view.
  411. ======================================================================================*/
  412.  
  413. void CMouseDragger::EndTracking(const SPoint32 *inStartMouseImagePt,
  414.                                 const SPoint32 *inEndMouseImagePt) {
  415.  
  416.     // Erase
  417.     DrawDragRegion(inStartMouseImagePt, inEndMouseImagePt, eDoErase);
  418. }
  419.  
  420.  
  421. /*======================================================================================
  422.     The mouse has reached a point that will cause the view to be scrolled. This method is
  423.     called just BEFORE the view is scolled to allow any dragging region to be erased
  424.     from the view before scrolling it. After the view is scrolled, the 
  425.     DoneScrollingView() method will be called. The input points represent the
  426.     last points passed to KeepTracking() if it has been called.
  427.  
  428.     All input points have been pinned to the bounds passed to DoTrackMouse() in the 
  429.     inMouseImagePinRect parameter and are also pinned to the frame of the view.
  430. ======================================================================================*/
  431.  
  432. void CMouseDragger::AboutToScrollView(const SPoint32 *inStartMouseImagePt,
  433.                                       const SPoint32 *inCurrMouseImagePt) {
  434.  
  435.     // Erase
  436.     DrawDragRegion(inStartMouseImagePt, inCurrMouseImagePt, eDoEraseScroll);
  437. }
  438.  
  439.  
  440. /*======================================================================================
  441.     The AboutToScrollView() was called and the view was just scolled. This method should
  442.     redraw any dragging region to the screen. The input points represent the NEW images
  443.     points of the mouse after scrolling.
  444.  
  445.     All input points have been pinned to the bounds passed to DoTrackMouse() in the 
  446.     inMouseImagePinRect parameter and are also pinned to the frame of the view.
  447. ======================================================================================*/
  448.  
  449. void CMouseDragger::DoneScrollingView(const SPoint32 *inStartMouseImagePt,
  450.                                       const SPoint32 *inCurrMouseImagePt) {
  451.  
  452.     // Draw
  453.     DrawDragRegion(inStartMouseImagePt, inCurrMouseImagePt, eDoDraw);
  454. }
  455.  
  456.  
  457. /*======================================================================================
  458.     Draw the draw region taking into the difference in mouse positions specified by
  459.     inStartMouseImagePt and inCurrMouseImagePt. inDrawState specifies whether to draw
  460.     the drag region or erase it.
  461. ======================================================================================*/
  462.  
  463. void CMouseDragger::DrawDragRegion(const SPoint32 *inStartMouseImagePt,
  464.                                    const SPoint32 *inCurrMouseImagePt,
  465.                                    EDrawRegionState inDrawState) {
  466.  
  467. }
  468.  
  469.  
  470. #pragma mark -
  471.  
  472. /*======================================================================================
  473.     This method is ALWAYS called from within the DoTrackMouse() method just before
  474.     the mouse tracking loop begins. If you want to setup instance varibles before
  475.     tracking begins, or draw an initial outline of a tracking image, this is the
  476.     place to do it. 
  477.     
  478.     The inStartMouseImagePt parameter has been pinned to the bounds passed to 
  479.     DoTrackMouse() in the inMouseImagePinRect parameter.
  480. ======================================================================================*/
  481.  
  482. void CTableRowDragger::BeginTracking(const SPoint32 * /* inStartMouseImagePt */)
  483. {
  484.  
  485.     mDidDraw = false;
  486.     Rect frame;
  487.     mView->CalcPortFrameRect(frame);
  488.  
  489.     mPortInsertionLineV = min_Int16;
  490.     mPortInsertionLineLeft = frame.left;
  491.     mPortInsertionLineRight = frame.right - 1;
  492.     mPortFrameMinV = frame.top;
  493.     mPortFrameMaxV = frame.bottom - 1;
  494.     
  495.     // Calculate rects for the arrows
  496.     mView->GetSuperView()->CalcPortFrameRect(frame);
  497.     
  498.     mPortLeftArrowBox.top = mPortRightArrowBox.top = -cArrowVCenterTopOffset;
  499.     mPortLeftArrowBox.right = frame.left - cArrowHMargin;
  500.     mPortLeftArrowBox.bottom = mPortRightArrowBox.bottom = mPortLeftArrowBox.top + cSmallIconHeight;
  501.     mPortLeftArrowBox.left = mPortLeftArrowBox.right - cSmallIconWidth;
  502.     mPortRightArrowBox.left = frame.right + cArrowHMargin;
  503.     mPortRightArrowBox.right = mPortRightArrowBox.left + cSmallIconWidth;
  504.  
  505.     LTableView *theTable = dynamic_cast<LTableView *>(mView);
  506.     Assert_(theTable != nil);
  507.     TableIndexT rows;
  508.     theTable->GetTableSize(rows, mNumCols);
  509. }
  510.  
  511.     
  512. /*======================================================================================
  513.     This method is ALWAYS called at the end of user mouse tracking. If the points
  514.     inStartMouseImagePt and inEndMouseImagePt not are equal, the user actually move 
  515.     the mouse somewhere different from where it started. This method should normally
  516.     erase any visual representation of a dragging region.
  517.  
  518.     All input points have been pinned to the bounds passed to DoTrackMouse() in the 
  519.     inMouseImagePinRect parameter.
  520. ======================================================================================*/
  521.  
  522. void CTableRowDragger::EndTracking(const SPoint32 *inStartMouseImagePt,
  523.                                       const SPoint32 *inEndMouseImagePt) {
  524.  
  525.     DrawDragRegion(inStartMouseImagePt, inEndMouseImagePt, eDoEraseScroll);
  526. }
  527.  
  528.     
  529. /*======================================================================================
  530.     Draw the local row rectangle taking into account the current and starting mouse
  531.     positions.
  532. ======================================================================================*/
  533.  
  534. void CTableRowDragger::DrawDragRegion(const SPoint32 *inStartMouseImagePt,
  535.                                         const SPoint32 *inCurrMouseImagePt,
  536.                                         EDrawRegionState inDrawState) {
  537.     
  538.     if ( !mDidDraw && (inDrawState != eDoDraw) ) return;    // Nothing to erase
  539.     
  540.     LTableView *theTable = dynamic_cast<LTableView *>(mView);
  541.     mDidDraw = true;
  542.     
  543.     // Calculate image rectangle to draw
  544.     
  545.     LImageRect drawImageRect;
  546.     {
  547.         SPoint32 topLeftPt, botRightPt;
  548.     
  549.         theTable->GetImageCellBounds(STableCell(mClickedRow, 1), topLeftPt.h, topLeftPt.v,
  550.                                       botRightPt.h, botRightPt.v);
  551.         if ( mNumCols > 1 ) {
  552.             SPoint32 tempPt;
  553.             theTable->GetImageCellBounds(STableCell(mClickedRow, mNumCols), tempPt.h, tempPt.v,
  554.                                           botRightPt.h, botRightPt.v);
  555.         }
  556.         Assert_((topLeftPt.v != 0) || (botRightPt.v != 0));
  557.         --botRightPt.v;
  558.         
  559.         drawImageRect.Set(topLeftPt.h, topLeftPt.v, botRightPt.h, botRightPt.v);
  560.         drawImageRect.Offset(inCurrMouseImagePt->h - inStartMouseImagePt->h,
  561.                              inCurrMouseImagePt->v - inStartMouseImagePt->v);
  562.     }
  563.                                  
  564.     // Setup the port
  565.  
  566.     if ( inDrawState == eDoDraw ) {
  567.         UpdateInsertionPoint(&drawImageRect, theTable, inDrawState);
  568.     }
  569.     
  570.     theTable->FocusDraw();
  571.     
  572.     StColorPenState::Normalize();
  573.  
  574.     ::PenMode(patXor);
  575.     ::PenPat(&UQDGlobals::GetQDGlobals()->gray);
  576.     
  577.     Rect rowRect;
  578.     CMouseDragger::ImageToLocalRect(theTable, &drawImageRect, &rowRect);
  579.  
  580.     ::FrameRect(&rowRect);
  581.     
  582.     ::PenNormal();
  583.     
  584.     if ( inDrawState != eDoDraw ) {
  585.         UpdateInsertionPoint(&drawImageRect, theTable, inDrawState);
  586.     }
  587. }
  588.  
  589.  
  590. /*======================================================================================
  591.     Update display of the insertion line.
  592. ======================================================================================*/
  593.  
  594. void CTableRowDragger::UpdateInsertionPoint(const LImageRect *inImageCellDrawRect,
  595.                                             LTableView *inTableView,
  596.                                             EDrawRegionState inDrawState) {
  597.     
  598.     // Calculate the current row we're over
  599.     
  600.     
  601.     STableCell hitCell;
  602.     SPoint32 curCenterPt;
  603.     
  604.     curCenterPt.h = inImageCellDrawRect->Left() + 
  605.                         ((inImageCellDrawRect->Right() - inImageCellDrawRect->Left()) / 2);
  606.     curCenterPt.v = inImageCellDrawRect->Top() +
  607.                         ((inImageCellDrawRect->Bottom() - inImageCellDrawRect->Top()) / 2);
  608.  
  609.     inTableView->GetCellHitBy(curCenterPt, hitCell);
  610.     Assert_(inTableView->IsValidRow(hitCell.row));
  611.     
  612.     Int16 newPortInsertionLineV = min_Int16;
  613.     
  614.     if ( inDrawState == eDoDraw ) {
  615.         
  616.         if ( hitCell.row != mClickedRow ) {
  617.         
  618.             TableIndexT    rows, cols;
  619.             inTableView->GetTableSize(rows, cols);
  620.  
  621.             // Adjust the cell so that mouse drawing occurs over the insertion line
  622.             SPoint32 topLeftPt, botRightPt;
  623.             
  624.             inTableView->GetImageCellBounds(hitCell, topLeftPt.h, topLeftPt.v,
  625.                                              botRightPt.h, botRightPt.v);
  626.                 
  627.             Assert_((topLeftPt.v != 0) || (botRightPt.v != 0));
  628.             Int32 cellMidV = topLeftPt.v + ((botRightPt.v - topLeftPt.v)>>1);
  629.             Boolean ignoreChanges = true;
  630.             
  631.             if ( curCenterPt.v >= cellMidV ) {
  632.                 if ( hitCell.row < mClickedRow ) {
  633.                     if ( hitCell.row < rows ) {
  634.                         ++hitCell.row;
  635.                         ignoreChanges = false;
  636.                     }
  637.                 }
  638.             } else {
  639.                 if ( hitCell.row > mClickedRow ) {
  640.                     if ( (hitCell.row > 1) && ((hitCell.row != rows) || (curCenterPt.v < cellMidV)) ) {
  641.                         --hitCell.row;
  642.                         ignoreChanges = false;
  643.                     }
  644.                 }
  645.             }
  646.             if ( !ignoreChanges ) {
  647.                 ignoreChanges = (hitCell.row != mClickedRow);
  648.                 if ( ignoreChanges ) {
  649.                     inTableView->GetImageCellBounds(hitCell, topLeftPt.h, topLeftPt.v,
  650.                                                      botRightPt.h, botRightPt.v);
  651.                     Assert_((topLeftPt.v != 0) || (botRightPt.v != 0));
  652.                 }
  653.             }
  654.             if ( ignoreChanges ) {
  655.                 Point portPoint;
  656.                 if ( hitCell.row > mClickedRow ) {
  657.                     CMouseDragger::ImageToPortPt(inTableView, &botRightPt, &portPoint);
  658.                     newPortInsertionLineV = portPoint.v;
  659.                 } else {
  660.                     CMouseDragger::ImageToPortPt(inTableView, &topLeftPt, &portPoint);
  661.                     newPortInsertionLineV = portPoint.v - 1;
  662.                 }
  663. #ifdef Debug_Signal
  664.                 {
  665.                     Rect portRect;
  666.                     LImageRect imageRect;
  667.                     inTableView->CalcPortFrameRect(portRect);
  668.                     CMouseDragger::PortToImageRect(inTableView, &portRect, &imageRect);
  669.                     Assert_(portRect.bottom >= newPortInsertionLineV);
  670.                     Assert_(portRect.top - 2 <= newPortInsertionLineV);
  671.                 }
  672. #endif // Debug_Signal
  673.             }
  674.         }
  675.         
  676.         mOverRow = hitCell.row;
  677.     }
  678.     
  679.     if ( (mPortInsertionLineV != newPortInsertionLineV) && (inDrawState != eDoErase) ) {
  680.     
  681.         LWindow *viewWindow = LWindow::FetchWindowObject(inTableView->GetMacPort());
  682.     
  683.         viewWindow->FocusDraw();
  684.         StColorPenState::Normalize();
  685.     
  686.         Int16 vPos;
  687.         Rect arrowLeft, arrowRight;
  688.         
  689.         // Erase old insertion line
  690.         
  691.         if ( mPortInsertionLineV != min_Int16 ) {
  692.             CalcArrowRects(mPortInsertionLineV, &arrowLeft, &arrowRight, true);
  693.             if ( mPortInsertionLineV < mPortFrameMinV ) {
  694.                 vPos = mPortFrameMinV;
  695.             } else if ( mPortInsertionLineV >= mPortFrameMaxV ) {
  696.                 vPos = mPortFrameMaxV;
  697.             } else {
  698.                 vPos = mPortInsertionLineV;
  699.                 ::PenSize(1, 2);
  700.             }
  701.             ::ForeColor(whiteColor);
  702.             ::MoveTo(mPortInsertionLineLeft, vPos);
  703.             ::LineTo(mPortInsertionLineRight, vPos);
  704.             
  705.             // Update insertion arrows
  706.             
  707.             viewWindow->InvalPortRect(&arrowLeft);
  708.             viewWindow->InvalPortRect(&arrowRight);
  709.             viewWindow->UpdatePort();
  710.             viewWindow->FocusDraw();
  711.  
  712. /* Old code that relies on ApplyForeAndBackColors()
  713.  
  714.             // Update insertion arrows
  715.             
  716.             inTableView->ApplyForeAndBackColors();
  717.             ::EraseRect(&arrowLeft);
  718.             ::EraseRect(&arrowRight);
  719.             ::ForeColor(blackColor);
  720.             ::PenSize(1, 1);
  721. */
  722.         }
  723.         
  724.         mPortInsertionLineV = newPortInsertionLineV;
  725.         
  726.         // Draw new insertion line
  727.         
  728.         if ( mPortInsertionLineV != min_Int16 ) {
  729.             CalcArrowRects(mPortInsertionLineV, &arrowLeft, &arrowRight, false);
  730.             if ( mPortInsertionLineV < mPortFrameMinV ) {
  731.                 vPos = mPortFrameMinV;
  732.             } else if ( mPortInsertionLineV >= mPortFrameMaxV ) {
  733.                 vPos = mPortFrameMaxV;
  734.             } else {
  735.                 vPos = mPortInsertionLineV;
  736.                 ::PenSize(1, 2);
  737.             }
  738.             ::MoveTo(mPortInsertionLineLeft, vPos);
  739.             ::LineTo(mPortInsertionLineRight, vPos);
  740.             ::PlotIconID(&arrowLeft, atNone, ttNone, icm8_LeftInsertArrow);
  741.             ::PlotIconID(&arrowRight, atNone, ttNone, icm8_RightInsertArrow);
  742.         }
  743.  
  744.         ::PenSize(1, 1);
  745.     }
  746. }
  747.  
  748.  
  749. /*======================================================================================
  750.     Update display of the insertion arrows.
  751. ======================================================================================*/
  752.  
  753. void CTableRowDragger::CalcArrowRects(Int16 inPortLineV, Rect *outLeftRect, Rect *outRightRect,
  754.                                         Boolean inErase) {
  755.     
  756.     // Calculate rects for the arrows
  757.         
  758.     *outLeftRect = mPortLeftArrowBox;
  759.     *outRightRect = mPortRightArrowBox;
  760.     ::OffsetRect(outLeftRect, 0, inPortLineV);
  761.     ::OffsetRect(outRightRect, 0, inPortLineV);
  762.     if ( inErase ) {
  763.         outLeftRect->left = outLeftRect->right - cArrowPolyWidth;
  764.         outRightRect->right = outRightRect->left + cArrowPolyWidth;
  765.     }
  766. }
  767.  
  768.  
  769.