home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODFDev / ODF / Framewrk / FWPart / Sources / FWScrolr.cpp < prev    next >
Encoding:
Text File  |  1996-08-16  |  28.6 KB  |  894 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                FWScrolr.cpp
  4. //    Release Version:    $ ODF 1 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWFrameW.hpp"
  11.  
  12. #ifndef FWSCROLR_H
  13. #include "FWScrolr.h"
  14. #endif
  15.  
  16. #ifndef FWPART_H
  17. #include "FWPart.h"
  18. #endif
  19.  
  20. #ifndef FWFRAME_H
  21. #include "FWFrame.h"
  22. #endif
  23.  
  24. #ifndef FWSCLNOT_H
  25. #include "FWSclNot.h"
  26. #endif
  27.  
  28. #ifndef FWITERS_H
  29. #include "FWIters.h"
  30. #endif
  31.  
  32. #ifndef FWUTIL_H
  33. #include "FWUtil.h"
  34. #endif
  35.  
  36. #ifndef FWSCLBAR_H
  37. #include "FWSclBar.h"
  38. #endif
  39.  
  40. #ifndef FWNOTDEF_H
  41. #include "FWNotDef.h"
  42. #endif
  43.  
  44. #ifndef FWCONTXT_H
  45. #include "FWContxt.h"
  46. #endif
  47.  
  48. // ----- Foundation Layer -----
  49.  
  50. #ifndef FWAROPER_H
  51. #include "FWArOper.h"
  52. #endif
  53.  
  54. // ----- OS Layer -----
  55.  
  56. #ifndef FWODGEOM_H
  57. #include "FWODGeom.h"
  58. #endif
  59.  
  60. #ifndef SLMIXOS_H
  61. #include "SLMixOS.h"
  62. #endif
  63.  
  64. // ----- OpenDoc Includes -----
  65.  
  66. #ifndef SOM_ODFacet_xh
  67. #include <Facet.xh>
  68. #endif
  69.  
  70. #ifndef SOM_ODSession_xh
  71. #include <ODSessn.xh>
  72. #endif
  73.  
  74. #ifndef SOM_ODTransform_xh
  75. #include <Trnsform.xh>
  76. #endif
  77.  
  78. #ifndef SOM_ODWindow_xh
  79. #include <Window.xh>
  80. #endif
  81.  
  82. #if defined(__MWERKS__) && GENERATING68K
  83. // A hack to work around a bug
  84. #pragma import list somGetGlobalEnvironment
  85. #endif
  86.  
  87. //========================================================================================
  88. // RunTime Info
  89. //========================================================================================
  90.  
  91. #ifdef FW_BUILD_MAC
  92. #pragma segment FW_FrameSegment
  93. #endif
  94.  
  95. //========================================================================================
  96. // CLASS FW_CPrivBaseScroller
  97. //========================================================================================
  98.  
  99. FW_DEFINE_CLASS_M0(FW_CPrivBaseScroller)
  100.  
  101. // This class is archivable, but we provide the archiving implementation in a separate
  102. // translation unit in order to enable deadstripping of the archiving-related code
  103. // in parts that do not use archiving with this class.
  104.  
  105. //----------------------------------------------------------------------------------------
  106. // FW_CPrivBaseScroller::FW_CPrivBaseScroller
  107. //----------------------------------------------------------------------------------------
  108.  
  109. FW_CPrivBaseScroller::FW_CPrivBaseScroller()
  110. {    
  111. }
  112.  
  113. //----------------------------------------------------------------------------------------
  114. // FW_CPrivBaseScroller::~FW_CPrivBaseScroller
  115. //----------------------------------------------------------------------------------------
  116.  
  117. FW_CPrivBaseScroller::~FW_CPrivBaseScroller()
  118. {    
  119. }
  120.  
  121. #ifdef FW_DEBUG
  122. //----------------------------------------------------------------------------------------
  123. //    FW_CPrivBaseScroller::PrivCheckFrame
  124. //----------------------------------------------------------------------------------------
  125.  
  126. void FW_CPrivBaseScroller::PrivCheckFrame(Environment* ev) const
  127. {
  128. FW_UNUSED(ev);
  129.     // Nothing to do. See FW_CScrollBarScroller::PrivCheckFrame
  130. }
  131. #endif
  132.  
  133. //========================================================================================
  134. // CLASS FW_CScroller
  135. //========================================================================================
  136.  
  137. FW_DEFINE_AUTO(FW_CScroller)
  138. FW_DEFINE_CLASS_M1(FW_CScroller, FW_CPrivBaseScroller)
  139.  
  140. // This class is archivable, but we provide the archiving implementation in a separate
  141. // translation unit in order to enable deadstripping of the archiving-related code
  142. // in parts that do not use archiving with this class.
  143.  
  144. //----------------------------------------------------------------------------------------
  145. // FW_CScroller::FW_CScroller
  146. //----------------------------------------------------------------------------------------
  147.  
  148. FW_CScroller::FW_CScroller(Environment* ev, FW_CFrame* frame) :
  149.     FW_CPrivBaseScroller(),
  150.     FW_MReceiver(),
  151.     fFrame(frame),
  152.     fAutoScrollIncrement(FW_kZeroPoint),    // By default no autoscroll
  153.     fAutoScrollInset(FW_IntToFixed(5)),
  154.     fLastAutoScrollTick(0)
  155. {
  156. FW_UNUSED(ev);
  157.     FW_ASSERT(fFrame);
  158.     
  159.     FW_END_CONSTRUCTOR
  160. }
  161.  
  162. //----------------------------------------------------------------------------------------
  163. // FW_CScroller::FW_CScroller
  164. //----------------------------------------------------------------------------------------
  165.  
  166. FW_CScroller::FW_CScroller(Environment* ev) :
  167.     FW_CPrivBaseScroller(),
  168.     FW_MReceiver(),
  169.     fFrame(0),
  170.     fAutoScrollIncrement(FW_kZeroPoint),    // By default no autoscroll
  171.     fAutoScrollInset(FW_IntToFixed(5)),
  172.     fLastAutoScrollTick(0)
  173. {
  174. FW_UNUSED(ev);
  175.     FW_END_CONSTRUCTOR
  176. }
  177.  
  178. //----------------------------------------------------------------------------------------
  179. // FW_CScroller::~FW_CScroller
  180. //----------------------------------------------------------------------------------------
  181.  
  182. FW_CScroller::~FW_CScroller()
  183. {
  184.     FW_START_DESTRUCTOR
  185. }
  186.  
  187. //----------------------------------------------------------------------------------------
  188. // FW_CScroller::RegisterScrollBar
  189. //----------------------------------------------------------------------------------------
  190.  
  191. void FW_CScroller::RegisterScrollNotifier(Environment* ev, FW_MNotifier* notifier)
  192. {
  193. FW_UNUSED(ev);
  194.     // create the interest for the scroll notification
  195.     AddInterest(FW_CInterest(notifier, FW_kScrollMsg));
  196. }
  197.  
  198. //----------------------------------------------------------------------------------------
  199. // FW_CScroller::UnregisterScrollNotifier
  200. //----------------------------------------------------------------------------------------
  201.  
  202. void FW_CScroller::UnregisterScrollNotifier(Environment* ev, FW_MNotifier* notifier)
  203. {
  204. FW_UNUSED(ev);
  205.     FW_CInterest interest(notifier, FW_kScrollMsg);
  206.     RemoveInterest(interest);
  207. }
  208.  
  209. //----------------------------------------------------------------------------------------
  210. // FW_CScroller::HandleNotification
  211. //----------------------------------------------------------------------------------------
  212.  
  213. void FW_CScroller::HandleNotification(Environment* ev, const FW_CNotification& notification)
  214. {
  215.     if (notification.GetMessage() == FW_kScrollMsg)
  216.     {
  217.         const FW_CScrollNotification& scrollNfy = (FW_CScrollNotification&) notification;
  218.     
  219.         FW_CPoint delta;
  220.         delta[scrollNfy.GetDirection(ev)] = -scrollNfy.GetDelta(ev);
  221.         
  222.         PrivChangeOffset(ev, 
  223.                     delta, 
  224.                     scrollNfy.ShouldScroll(ev));    // I don't want to update right now    
  225.     }
  226. }
  227.  
  228. //----------------------------------------------------------------------------------------
  229. // FW_CScroller::ScrollDraw
  230. //----------------------------------------------------------------------------------------
  231. //    [HLX] Need a try block
  232.  
  233. void FW_CScroller::ScrollDraw(Environment* ev, ODFacet* facet, const FW_CPoint& by)
  234. {
  235. #ifdef FW_BUILD_MAC
  236.     ODPlatformWindow platformWindow = facet->GetWindow(ev)->GetPlatformWindow(ev);
  237.     
  238.     GrafPtr port;
  239.     ::GetPort(&port);
  240.     ::SetPort(platformWindow);
  241.     Point origin;
  242.     origin.h = platformWindow->portRect.left;
  243.     origin.v = platformWindow->portRect.top;
  244.     ODRgnHandle clipRgn = ::NewRgn();
  245.     ::GetClip(clipRgn);
  246.     
  247.     ::SetOrigin(0, 0);
  248.     
  249.     FW_CAcquiredODShape aqScrollShape = PrivAcquireContentScrollShape(ev, (by.x != FW_kFixed0), (by.y != FW_kFixed0));    
  250.  
  251.     // converts to window coordinates    
  252.     FW_CAcquiredODTransform aqWindowFrameTransform = facet->AcquireWindowFrameTransform(ev, NULL);
  253.     aqScrollShape->Transform(ev, aqWindowFrameTransform);
  254.     
  255.     FW_CPlatformRect platformRect = FW_GetShapeBoundingBox(ev, aqScrollShape);
  256.     
  257.     // get clip shape in window coordinates & intersect with scrollShape
  258.     FW_CAcquiredODShape aqAggregateClipShape = FW_CopyAndRelease(ev, facet->AcquireAggregateClipShape(ev, NULL));
  259.     aqAggregateClipShape->Transform(ev, aqWindowFrameTransform);
  260.     
  261.     aqAggregateClipShape->Intersect(ev, aqScrollShape);
  262.     
  263.     RgnHandle aggregateClipRgn = aqAggregateClipShape->GetQDRegion(ev);
  264.     ::SetClip(aggregateClipRgn);
  265.     
  266.     RgnHandle invalidRgn = ::NewRgn();    // will be adopted by aqInvalidShape. No need to dispose it
  267.     ::ScrollRect(&platformRect, by.IntX(), by.IntY(), invalidRgn);
  268.     
  269.     FW_CAcquiredODShape aqInvalidShape = ::FW_NewODShape(ev, invalidRgn);
  270.     aqInvalidShape->InverseTransform(ev, aqWindowFrameTransform);
  271.  
  272.     // ----- Validating all the embedded facets seems to make it a little bit faster
  273. //    FW_CFacetIterator ite(ev, facet, kODChildrenOnly, kODFrontToBack);
  274. //    for (ODFacet* embeddedFacet = ite.First(ev); ite.IsNotComplete(ev); embeddedFacet = ite.Next(ev))
  275. //    {
  276. //        embeddedFacet->Validate(ev, NULL, NULL);
  277. //    }    
  278.  
  279.     // ----- Update the facet -----
  280.     facet->Invalidate(ev, aqInvalidShape, NULL);
  281.     facet->GetWindow(ev)->Update(ev);
  282.     
  283.     ::SetPort(platformWindow);
  284.     ::SetClip(clipRgn);
  285.     ::DisposeRgn(clipRgn);
  286.     ::SetOrigin(-origin.h, -origin.v);
  287.     ::SetPort(port);
  288. #endif
  289.  
  290. #ifdef FW_BUILD_WIN
  291.     FW_DEBUG_MESSAGE("Needs to be redone");
  292. #endif
  293. }
  294.  
  295. //----------------------------------------------------------------------------------------
  296. //    FW_CScroller::ScaleBy
  297. //----------------------------------------------------------------------------------------
  298.  
  299. void FW_CScroller::ScaleBy(Environment* ev, const FW_CPoint& scaling, FW_CGraphicContext* gc)
  300. {
  301.     FW_ASSERT(scaling.x != FW_kFixed0 && scaling.y != FW_kFixed0);
  302.     
  303.     FW_CAcquiredODTransform aqInternal = fFrame->AcquireInternalTransform(ev);
  304.     FW_CPoint contentLocation = fFrame->PrivGetContentViewOffset(ev);
  305.     
  306.     aqInternal->MoveBy(ev, (ODPoint*)&(-contentLocation));
  307.     
  308.     FW_CPoint prevScaling;
  309.     aqInternal->GetScale(ev, (ODPoint*)&prevScaling);
  310.     aqInternal->ScaleDownBy(ev, (ODPoint*)&prevScaling);
  311.     
  312.     aqInternal->ScaleBy(ev, (ODPoint*)&scaling);
  313.     aqInternal->MoveBy(ev, (ODPoint*)&contentLocation);
  314.     
  315.     fFrame->ChangeInternalTransform(ev, aqInternal);
  316.     
  317.     UpdateScrollParameters(ev);
  318.     
  319.     if (gc)
  320.         gc->Reset();
  321.         
  322.     fFrame->Invalidate(ev);    // Invalidate the whole frame
  323. }
  324.  
  325. //----------------------------------------------------------------------------------------
  326. //    FW_CScroller::PrivChangeOffset
  327. //----------------------------------------------------------------------------------------
  328.  
  329. void FW_CScroller::PrivChangeOffset(Environment* ev, const FW_CPoint& offset, FW_Boolean scroll)
  330. {
  331.     FW_CPoint temp(offset);
  332.     
  333.     FW_CAcquiredODTransform aqFrameInternal = fFrame->AcquireInternalTransform(ev);
  334.     
  335.     FW_CPoint scale;
  336.     aqFrameInternal->GetScale(ev, (ODPoint*)&scale);
  337.     temp.x *= scale.x;
  338.     temp.y *= scale.y;
  339.     aqFrameInternal->MoveBy(ev, (ODPoint*)&temp);
  340.     
  341.     fFrame->ChangeInternalTransform(ev, aqFrameInternal);
  342.  
  343.     if (scroll)
  344.     {
  345.         // ------ Scroll all Facets of the frame
  346.         FW_CFrameFacetIterator ite(ev, fFrame);
  347.         for (ODFacet* facet = ite.First(ev); ite.IsNotComplete(ev); facet = ite.Next(ev))
  348.         {
  349.             this->ScrollDraw(ev, facet, temp);
  350.         }
  351.     }
  352.     
  353.     ScrollPositionChanged(ev);
  354. }
  355.  
  356. //----------------------------------------------------------------------------------------
  357. // FW_CScroller::UpdateScrollParameters
  358. //----------------------------------------------------------------------------------------
  359.  
  360. void FW_CScroller::UpdateScrollParameters(Environment* ev, FW_Boolean notify)
  361. {
  362. FW_UNUSED(ev);
  363. FW_UNUSED(notify);
  364. }
  365.  
  366. //----------------------------------------------------------------------------------------
  367. // FW_CScroller::ScrollPositionChanged
  368. //----------------------------------------------------------------------------------------
  369.  
  370. void FW_CScroller::ScrollPositionChanged(Environment* ev)
  371. {
  372. FW_UNUSED(ev);
  373. }
  374.  
  375. //----------------------------------------------------------------------------------------
  376. // FW_CScroller::InitializeAutoScroll
  377. //----------------------------------------------------------------------------------------
  378.  
  379. void FW_CScroller::InitializeAutoScroll(Environment* ev)
  380. {
  381. FW_UNUSED(ev);
  382.  
  383.     fAutoScrollStage = kOutStage;
  384. }
  385.  
  386. //----------------------------------------------------------------------------------------
  387. // FW_CScroller::GetScrollUnits
  388. //----------------------------------------------------------------------------------------
  389. //    GetScrollUnits by default returns 1/10 of the size of the visible content for minor and
  390. //    the size of the visible content for major
  391.  
  392. void FW_CScroller::GetScrollUnits(Environment* ev, FW_Fixed& minor, FW_Fixed& major, FW_XYSelector direction)
  393. {
  394.     FW_CPoint visibleContentSize = fFrame->GetContentView(ev)->GetBoundsInContent(ev).Size();
  395.  
  396.     minor = FW_IntToFixed(FW_FixedToInt(visibleContentSize[direction]) / 10);
  397.     major = FW_RoundedToInt(visibleContentSize[direction]);
  398. }
  399.  
  400. //----------------------------------------------------------------------------------------
  401. // FW_PrivLimitScrolling
  402. //----------------------------------------------------------------------------------------
  403. //    Don't forget positive offset means we are scrolling down so the scrollingArea is going
  404. //    up in the extent
  405.  
  406. static void FW_PrivLimitScrolling(const FW_CPoint& extent, const FW_CRect& scrollingArea, FW_CPoint& scrollBy)
  407. {
  408.     if (scrollingArea.left - scrollBy.x < FW_kFixed0)
  409.         scrollBy.x = scrollingArea.left;
  410.     if (scrollingArea.right - scrollBy.x > extent.x)
  411.         scrollBy.x = scrollingArea.right - extent.x;
  412.     
  413.     if (scrollingArea.top - scrollBy.y < FW_kFixed0)
  414.         scrollBy.y = scrollingArea.top;
  415.     if (scrollingArea.bottom - scrollBy.y > extent.y)
  416.         scrollBy.y = scrollingArea.bottom - extent.y;
  417. }
  418.  
  419. //----------------------------------------------------------------------------------------
  420. // FW_CScroller::AutoScrollOffset
  421. //----------------------------------------------------------------------------------------
  422.  
  423. FW_CPoint FW_CScroller::AutoScrollOffset(Environment* ev, 
  424.                                         const FW_CPoint& currentPoint, 
  425.                                         unsigned long delay)
  426. {
  427.     FW_CPoint scroll(FW_kZeroPoint);
  428.     
  429.     if (fAutoScrollIncrement != FW_kZeroPoint)
  430.     {
  431.         FW_CPoint delta;
  432.         
  433.         FW_CSuperView* contentView = fFrame->GetContentView(ev);
  434.         FW_CRect content = contentView->GetBoundsInContent(ev);
  435.         FW_CRect bounds(content);
  436.         
  437.         bounds.Inset(fAutoScrollInset);
  438.         
  439.         switch (::FW_RegionCode(currentPoint, bounds))
  440.         {
  441.             case 9:
  442.                 scroll = fAutoScrollIncrement;
  443.                 delta.x = currentPoint.x - content.left;
  444.                 delta.y = currentPoint.y - content.top;
  445.                 break;
  446.             case 1:
  447.                 scroll.y = fAutoScrollIncrement.y;
  448.                 delta.y = currentPoint.y - content.top;
  449.                 break;
  450.             case 5:
  451.                 scroll.x = -fAutoScrollIncrement.x;
  452.                 scroll.y = fAutoScrollIncrement.y;
  453.                 delta.x = content.right - currentPoint.x;
  454.                 delta.y = currentPoint.y - content.top;
  455.                 break;
  456.             case 8:
  457.                 scroll.x = fAutoScrollIncrement.x;
  458.                 delta.x = currentPoint.x - content.left;
  459.                 break;
  460.             case 4:
  461.                 scroll.x = -fAutoScrollIncrement.x;
  462.                 delta.x = content.right - currentPoint.x;
  463.                 break;
  464.             case 10:
  465.                 scroll.x = fAutoScrollIncrement.x;
  466.                 scroll.y = -fAutoScrollIncrement.y;
  467.                 delta.x = currentPoint.x - content.left;
  468.                 delta.y = content.bottom - currentPoint.y;
  469.                 break;
  470.             case 2:
  471.                 scroll.y = -fAutoScrollIncrement.y;
  472.                 delta.y = content.bottom - currentPoint.y;
  473.                 break;
  474.             case 6:
  475.                 scroll = -fAutoScrollIncrement;
  476.                 delta.x = content.right - currentPoint.x;
  477.                 delta.y = content.bottom - currentPoint.y;
  478.                 break;
  479.         }
  480.         
  481.         if (scroll != FW_kZeroPoint)
  482.         {
  483.             if (delta.x < FW_kFixed0)
  484.                 delta.x = FW_kFixed0;
  485.             if (delta.y < FW_kFixed0)
  486.                 delta.y = FW_kFixed0;
  487.             
  488.             scroll.x = FW_RoundedToInt(((fAutoScrollInset - delta.x) * scroll.x) / fAutoScrollInset);
  489.             scroll.y = FW_RoundedToInt(((fAutoScrollInset - delta.y) * scroll.y) / fAutoScrollInset);
  490.             
  491.             FW_PrivLimitScrolling(contentView->GetExtent(ev), content, scroll);
  492.             
  493.             if (delay != 0)
  494.             {
  495.                 if (fAutoScrollStage == kOutStage)
  496.                 {
  497.                     fLastAutoScrollTick = ::FW_GetTickCount();
  498.                     fAutoScrollStage = kDelayStage;
  499.                     scroll = FW_kZeroPoint;
  500.                 }                    
  501.                 else if (fAutoScrollStage == kDelayStage)
  502.                 {
  503.                     if (::FW_GetTickCount() - fLastAutoScrollTick < delay)
  504.                         scroll = FW_kZeroPoint;
  505.                     else
  506.                         fAutoScrollStage = kScrollStage;
  507.                 }            
  508.             }                        
  509.         
  510.             // ----- Make sure that we don't scroll in an unwanted direction -----
  511.             if (fAutoScrollIncrement.x == FW_kFixed0)
  512.                 scroll.x = FW_kFixed0;
  513.             if (fAutoScrollIncrement.y == FW_kFixed0)
  514.                 scroll.y = FW_kFixed0;
  515.         }
  516.         else
  517.             fAutoScrollStage = kOutStage;
  518.     }
  519.     
  520.     return scroll;
  521. }
  522.  
  523. //----------------------------------------------------------------------------------------
  524. // FW_CScroller::ScrollBy
  525. //----------------------------------------------------------------------------------------
  526. //    a positive offset means we are scrolling down (down arrow)
  527.  
  528. void FW_CScroller::ScrollBy(Environment* ev, const FW_CPoint& offset, FW_CGraphicContext* gc)
  529. {
  530.     // ----- Validate the offset -----
  531.     FW_CSuperView* contentView = fFrame->GetContentView(ev);
  532.     FW_ASSERT(contentView);
  533.     
  534.     FW_CPoint scroll(offset);
  535.     FW_PrivLimitScrolling(contentView->GetExtent(ev), contentView->GetBoundsInContent(ev), scroll);
  536.         
  537.     PrivScrollBy(ev, scroll, gc);
  538. }
  539.  
  540. //----------------------------------------------------------------------------------------
  541. // FW_CScroller::PrivScrollBy
  542. //----------------------------------------------------------------------------------------
  543. //    PrivScrollBy doesn't make any validation on the offset
  544.  
  545. void FW_CScroller::PrivScrollBy(Environment* ev, const FW_CPoint& offset, FW_CGraphicContext* gc)
  546. {
  547.     if (offset != FW_kZeroPoint)
  548.     {
  549.         // ----- We don't support scrolling in two directions at the same time so...
  550.         if (offset.x != FW_kFixed0)
  551.             PrivChangeOffset(ev, FW_CPoint(offset.x, FW_kFixed0), TRUE);
  552.         if (offset.y != FW_kFixed0)
  553.             PrivChangeOffset(ev, FW_CPoint(FW_kFixed0, offset.y), TRUE);
  554.             
  555.         if (gc)
  556.             gc->Reset();            
  557.     }
  558. }
  559.  
  560. //----------------------------------------------------------------------------------------
  561. // FW_CScroller::AutoScroll
  562. //----------------------------------------------------------------------------------------
  563. //    currentPoint is in content coordinates
  564.  
  565. void FW_CScroller::AutoScroll(Environment* ev, 
  566.                                 const FW_CPoint& currentPoint, 
  567.                                 FW_CGraphicContext* gc,
  568.                                 unsigned long delay)
  569. {    
  570.     PrivScrollBy(ev, AutoScrollOffset(ev, currentPoint, delay), gc);
  571. }
  572.  
  573. //----------------------------------------------------------------------------------------
  574. // FW_CScroller::PrivAcquireContentScrollShape
  575. //----------------------------------------------------------------------------------------
  576. // This returns the shape (in Frame coord.) composed of the ContentView + all the views
  577. // scrolling in X or Y with the content.  
  578. // [LSD] if scroll is not purely X or Y we limit the shape to the ContentView for now.
  579. //         Other views will have to scroll independantly
  580.  
  581. ODShape* FW_CScroller::PrivAcquireContentScrollShape(Environment* ev, FW_Boolean horizontalScroll, FW_Boolean verticalScroll) const
  582. {
  583.     FW_CSuperView* contentView = fFrame->GetContentView(ev);
  584.     FW_ASSERT(contentView);
  585.     
  586.     // ----- Get the contentView first
  587.     ODShape* scrollShape = ::FW_NewODShape(ev, FW_CRect(FW_kZeroPoint, contentView->GetSize(ev)));
  588.     contentView->ViewToFrame(ev, scrollShape);
  589.  
  590.     // ----- Does not support both scrolling directions
  591.     if ((!verticalScroll || !horizontalScroll) && (verticalScroll || horizontalScroll))
  592.         fFrame->PrivAcquireContentScrollShape(ev, horizontalScroll, verticalScroll, scrollShape);    
  593.     
  594.     return scrollShape;
  595. }
  596.  
  597. //----------------------------------------------------------------------------------------
  598. //    FW_CScroller::Flatten
  599. //----------------------------------------------------------------------------------------
  600.  
  601. void FW_CScroller::Flatten(Environment* ev, FW_CWritableStream& stream) const
  602. {
  603.     FW_CFrame* frame = fFrame;
  604. #ifdef FW_DEBUG
  605.     FW_OObjectRegistry*    registry = stream.GetRegistry();
  606.     frame = (FW_CFrame*) registry->LookupByID(ev, FW_kPreregisteredFrameObject);
  607.     FW_ASSERT(frame == fFrame);
  608. #else
  609. FW_UNUSED(ev);
  610. #endif
  611.  
  612.     FW_WRITE_DYNAMIC_OBJECT(stream, frame, FW_CFrame);
  613.     stream << fAutoScrollInset;
  614.     stream << fAutoScrollIncrement;
  615. }
  616.  
  617. //----------------------------------------------------------------------------------------
  618. //    FW_CScroller::InitializeFromStream
  619. //----------------------------------------------------------------------------------------
  620.  
  621. void FW_CScroller::InitializeFromStream(Environment* ev, FW_CReadableStream& stream)
  622. {
  623. #ifdef FW_DEBUG
  624.     FW_OObjectRegistry*    registry = stream.GetRegistry();
  625.     FW_CFrame* frame = (FW_CFrame*) registry->LookupByID(ev, FW_kPreregisteredFrameObject);
  626.     FW_ASSERT(frame != 0);
  627. #else
  628. FW_UNUSED(ev);
  629. #endif
  630.  
  631.     FW_READ_DYNAMIC_OBJECT(stream, &fFrame, FW_CFrame);
  632.     FW_ASSERT(frame == fFrame);
  633.     
  634.     stream >> fAutoScrollInset;
  635.     stream >> fAutoScrollIncrement;
  636. }
  637.  
  638. //========================================================================================
  639. // CLASS FW_CScrollBarScroller
  640. //========================================================================================
  641.  
  642. FW_DEFINE_AUTO(FW_CScrollBarScroller)
  643. FW_DEFINE_CLASS_M1(FW_CScrollBarScroller, FW_CScroller)
  644.  
  645. // This class is archivable, but we provide the archiving implementation in a separate
  646. // translation unit in order to enable deadstripping of the archiving-related code
  647. // in parts that do not use archiving with this class.
  648.  
  649. //----------------------------------------------------------------------------------------
  650. // FW_CScrollBarScroller::FW_CScrollBarScroller
  651. //----------------------------------------------------------------------------------------
  652.  
  653. FW_CScrollBarScroller::FW_CScrollBarScroller(Environment* ev, 
  654.                                              FW_CFrame* frame,
  655.                                              FW_CScrollBar* horzSB, 
  656.                                              FW_CScrollBar* vertSB) :
  657.     FW_CScroller(ev, frame)
  658. {
  659.     fScrollbars[FW_kHorizontal] = horzSB;
  660.     fScrollbars[FW_kVertical] = vertSB;
  661.     
  662.     if (fScrollbars[FW_kHorizontal])
  663.         RegisterScrollNotifier(ev, fScrollbars[FW_kHorizontal]);
  664.     if (fScrollbars[FW_kVertical])
  665.         RegisterScrollNotifier(ev, fScrollbars[FW_kVertical]);
  666.     
  667.     FW_END_CONSTRUCTOR
  668. }
  669.  
  670. //----------------------------------------------------------------------------------------
  671. // FW_CScrollBarScroller::FW_CScrollBarScroller
  672. //----------------------------------------------------------------------------------------
  673.  
  674. FW_CScrollBarScroller::FW_CScrollBarScroller(Environment* ev) :
  675.     FW_CScroller(ev)
  676. {
  677.     FW_END_CONSTRUCTOR
  678. }
  679.  
  680. //----------------------------------------------------------------------------------------
  681. // FW_CScrollBarScroller::~FW_CScrollBarScroller
  682. //----------------------------------------------------------------------------------------
  683.  
  684. FW_CScrollBarScroller::~FW_CScrollBarScroller()
  685. {
  686.     FW_START_DESTRUCTOR
  687.     
  688.     // Don't delete the scroll bars, we don't own them! The containing gadget
  689.     // or frame owns them.
  690.     
  691.     Environment* ev = ::somGetGlobalEnvironment();
  692.     
  693.     if (fScrollbars[FW_kHorizontal])
  694.         UnregisterScrollNotifier(ev, fScrollbars[FW_kHorizontal]);
  695.     if (fScrollbars[FW_kVertical])
  696.         UnregisterScrollNotifier(ev, fScrollbars[FW_kVertical]);
  697. }
  698.  
  699. //----------------------------------------------------------------------------------------
  700. // SetThumbPosition
  701. //----------------------------------------------------------------------------------------
  702.  
  703. static void SetThumbPosition(Environment* ev, FW_CScrollBar* sb, FW_Fixed pos)
  704. {
  705.     FW_Fixed oldPos = sb->GetScrollPos(ev);    
  706.     FW_Fixed newPos = FW_RoundedToInt(pos);    
  707.     if (oldPos != newPos)
  708.         sb->SetScrollPos(ev, newPos);    
  709. }
  710.  
  711. //----------------------------------------------------------------------------------------
  712. // FW_CScrollBarScroller::ScrollPositionChanged
  713. //----------------------------------------------------------------------------------------
  714.  
  715. void FW_CScrollBarScroller::ScrollPositionChanged(Environment* ev)
  716. {
  717.     FW_CSuperView* contentView = fFrame->GetContentView(ev);
  718.     if (contentView == NULL)
  719.         return;
  720.  
  721.     FW_CRect visibleContent = contentView->GetBoundsInContent(ev);
  722.  
  723.     FW_CScrollBar* sb = fScrollbars[FW_kVertical];
  724.     if (sb != NULL)
  725.         SetThumbPosition(ev, sb, visibleContent.top);
  726.  
  727.     sb = fScrollbars[FW_kHorizontal];
  728.     if (sb != NULL)
  729.         SetThumbPosition(ev, sb, visibleContent.left);
  730. }
  731.  
  732. //----------------------------------------------------------------------------------------
  733. // FW_CScrollBarScroller::PrivAdjustScrollBar
  734. //----------------------------------------------------------------------------------------
  735.  
  736. FW_Boolean FW_CScrollBarScroller::PrivAdjustScrollBar(Environment* ev, 
  737.                                                         FW_XYSelector direction, 
  738.                                                         FW_Fixed visibleContent,
  739.                                                         FW_Fixed contentExtent,
  740.                                                         FW_Fixed contentOffset,
  741.                                                         FW_Boolean notify)
  742. {
  743.     FW_CScrollBar* sb = fScrollbars[direction];
  744.     if (sb == NULL)
  745.         return FALSE;
  746.     
  747.     FW_Fixed oldPos = sb->GetScrollPos(ev);
  748.     FW_Fixed scrollMin = sb->GetScrollMin(ev);
  749.     
  750.     // ----- Update scrollbar Major and Minor scroll units
  751.     FW_Fixed minor, major;
  752.     GetScrollUnits(ev, minor, major, direction);
  753.     
  754.     sb->SetMinorScrollUnits(ev, minor);
  755.     sb->SetMajorScrollUnits(ev, major);
  756.  
  757.     // ----- calculate the maximum
  758.     FW_Fixed maxOffset = FW_RoundedToInt(FW_Maximum(contentExtent - visibleContent, FW_kFixed0));
  759.     
  760.     sb->SetScrollMax(ev, scrollMin + maxOffset);
  761.     
  762.     // ----- Calculate the new position -----
  763.     FW_Fixed newPos = FW_RoundedToInt(FW_Minimum(contentOffset, maxOffset));
  764.         
  765.     FW_Boolean positionChanged = (newPos != oldPos);
  766.     
  767.     if (newPos < scrollMin)
  768.         newPos = scrollMin;
  769.  
  770.     if (positionChanged)
  771.     {
  772.         sb->SetScrollPos(ev, maxOffset, newPos);
  773.         newPos = sb->GetScrollPos(ev);        // I need to do that because of rounding
  774.         
  775.         if (notify)
  776.             sb->ScrollPositionChanged(ev, newPos - oldPos, FALSE);    // Don't scroll
  777.     }
  778.     
  779.     return positionChanged;
  780. }
  781.  
  782. //----------------------------------------------------------------------------------------
  783. // FW_CScrollBarScroller::UpdateScrollParameters
  784. //----------------------------------------------------------------------------------------
  785.  
  786. void FW_CScrollBarScroller::UpdateScrollParameters(Environment* ev, FW_Boolean notify)
  787. {
  788.     FW_CSuperView* contentView = fFrame->GetContentView(ev);
  789.     if (contentView == NULL)
  790.         return;
  791.     
  792.     FW_CRect visibleContent = contentView->GetBoundsInContent(ev);
  793.     FW_CPoint extent = contentView->GetExtent(ev);
  794.  
  795.     if (PrivAdjustScrollBar(ev, FW_kVertical, visibleContent.Height(), extent.y, visibleContent.top, notify))
  796.     {
  797.         FW_CAcquiredODShape invalidShape =    PrivAcquireContentScrollShape(ev, FALSE, TRUE);
  798.         fFrame->GetODFrame(ev)->Invalidate(ev, invalidShape, NULL);
  799.     }
  800.     
  801.     if (PrivAdjustScrollBar(ev, FW_kHorizontal, visibleContent.Width(), extent.x, visibleContent.left, notify))
  802.     {
  803.         FW_CAcquiredODShape invalidShape =    PrivAcquireContentScrollShape(ev, TRUE, FALSE);
  804.         fFrame->GetODFrame(ev)->Invalidate(ev, invalidShape, NULL);
  805.     }
  806. }
  807.  
  808. //----------------------------------------------------------------------------------------
  809. //    FW_CScrollBarScroller::RemoveScrollBar
  810. //----------------------------------------------------------------------------------------
  811. // This doesn't delete the scrollbar view itself
  812.  
  813. void FW_CScrollBarScroller::RemoveScrollBar(Environment* ev, FW_XYSelector direction) 
  814. {
  815. FW_UNUSED(ev);
  816.     FW_CScrollBar* sb = fScrollbars[direction];
  817.     if (sb == NULL)
  818.         return;
  819.     
  820.     // Remove the connection first    
  821.     RemoveInterest(FW_CInterest(sb, FW_kScrollMsg));
  822.     
  823.     fScrollbars[direction] = NULL;
  824. }
  825.  
  826. //----------------------------------------------------------------------------------------
  827. //    FW_CScrollBarScroller::Flatten
  828. //----------------------------------------------------------------------------------------
  829.  
  830. void FW_CScrollBarScroller::Flatten(Environment* ev, FW_CWritableStream& stream) const
  831. {
  832.     FW_CScroller::Flatten(ev, stream);
  833.     ODID horizScrollBarID = kODNULLID;
  834.     ODID vertScrollBarID = kODNULLID;
  835.     
  836.     if (fScrollbars[FW_kHorizontal])
  837.         horizScrollBarID = fScrollbars[FW_kHorizontal]->GetViewId(ev);
  838.     if (fScrollbars[FW_kVertical])
  839.         vertScrollBarID = fScrollbars[FW_kVertical]->GetViewId(ev);
  840.  
  841.     stream << horizScrollBarID << vertScrollBarID;
  842. }
  843.  
  844. //----------------------------------------------------------------------------------------
  845. //    FW_CScrollBarScroller::InitializeFromStream
  846. //----------------------------------------------------------------------------------------
  847.  
  848. void FW_CScrollBarScroller::InitializeFromStream(Environment* ev, FW_CReadableStream& stream)
  849. {
  850.     FW_CScroller::InitializeFromStream(ev, stream);
  851.  
  852.     ODID horizScrollBarID;
  853.     ODID vertScrollBarID;
  854.     stream >> horizScrollBarID >> vertScrollBarID;
  855.  
  856.     FW_CView* hScrollBarView = NULL;
  857.     if (horizScrollBarID != kODNULLID)
  858.         hScrollBarView = fFrame->FindViewById(ev, horizScrollBarID);
  859.  
  860.     FW_CView* vScrollBarView = NULL;
  861.     if (vertScrollBarID != kODNULLID)
  862.         vScrollBarView = fFrame->FindViewById(ev, vertScrollBarID);
  863.  
  864.     fScrollbars[FW_kHorizontal] = FW_DYNAMIC_CAST(FW_CScrollBar, hScrollBarView);
  865.     fScrollbars[FW_kVertical] = FW_DYNAMIC_CAST(FW_CScrollBar, vScrollBarView);
  866.     
  867.     if (fScrollbars[FW_kHorizontal])
  868.         RegisterScrollNotifier(ev, fScrollbars[FW_kHorizontal]);
  869.     
  870.     if (fScrollbars[FW_kVertical])
  871.         RegisterScrollNotifier(ev, fScrollbars[FW_kVertical]);
  872. }
  873.  
  874. #ifdef FW_DEBUG
  875. //----------------------------------------------------------------------------------------
  876. //    FW_CScrollBarScroller::PrivCheckFrame
  877. //----------------------------------------------------------------------------------------
  878.  
  879. void FW_CScrollBarScroller::PrivCheckFrame(Environment* ev) const
  880. {
  881.     // We cannot authorize frames to use a scroller with scrollbars in case they don't have 
  882.     // a separate content view, because the scrollbars will end up moving with the rest of 
  883.     // frame's content!  A frame which is its own content view  can only use a basic
  884.     // FW_CScroller instance, which can be scrolled with a hand-scrolling or auto-scrolling
  885.     // mechanism.
  886.  
  887.     if (fFrame->IsContentView(ev))
  888.     {
  889.         FW_DEBUG_MESSAGE("Cannot use a ScrollBarScroller here, create a separate content view");
  890.     }
  891.  
  892. }
  893. #endif
  894.