home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 2 / ETO Development Tools 2.iso / Tools - Objects / MacApp / MacApp CD Release / MacApp 2.0.1 (Many Libraries) / Examples / Calc / USynchScroller.p < prev   
Encoding:
Text File  |  1990-10-25  |  9.8 KB  |  270 lines  |  [TEXT/MPS ]

  1. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  2. { USynchScroller.p }
  3. { Copyright © 1989-1990 by Apple Computer Inc. All rights reserved. }
  4.  
  5. {[f-]}
  6. (*
  7.         T H E O R Y   O F    O P E R A T I O N
  8.  
  9. This is Larry Tesler's excellent unit: USynchScroller, that supports smoother
  10. synchronized scrolling.  It addresses two problems.
  11.  
  12. Problem 1: In programs like Calc and DoubleVision, when the main view scrolls,
  13. the side and/or top views scroll by the same amount.  However, each view scrolls
  14. using a separate ScrollRect, causing a jumpy appearance, especially when redraw
  15. time is significant.
  16.  
  17. Problem 2: Packaging the synchronous scrolling functionality of (the old) Calc as a
  18. building block would be difficult.    In addition to defining a special subclass
  19. of TScroller for the main view's scroller, Calc used to override methods of the side
  20. views themselves, as well as methods of various command objects.
  21.  
  22. Solution: Combine ideas from both Calc and DoubleVision.  USynchScroller
  23. defines a subclass of TScroller:
  24.     TSynchScroller
  25. and two subclasses of TSynchScroller:
  26.     TPrimaryScroller
  27.     TSecondaryScroller
  28. A primary scroller can control a list of secondary scrollers.  The scroll bars
  29. belong exclusively to the primary scroller.
  30.  
  31. The extent and scrollLimit of a secondary scroller must match those of the
  32. primary scroller in the pertinent axis.  There are other constraints as well--
  33. most or all of which are obvious--that are documented herein.
  34.  
  35. The unit overrides the following methods of TScroller:
  36.     In TSynchScroller:
  37.         SetScrollLimits
  38.     In TPrimaryScroller and TSecondaryScroller:
  39.         DoScroll
  40.         Fields
  41.     In TPrimaryScroller only:
  42.         ScrollDraw
  43.  
  44. It also implements a method, TPrimaryScroller.AddSecondaryScroller, to connect the
  45. primary scroller bidirectionally with each of its secondary scrollers.    Once connected,
  46. the following behavior transpires to perform scrolling, whether invoked by the
  47. scroll bars, function keys, or autoscrolling:
  48.  
  49.     When addressed to the primary scroller:
  50.         -> TPrimaryScroller.ScrollBy
  51.             -> TPrimaryScroller.DoScroll
  52.                 -> TPrimaryScroller.ScrollDraw
  53.                         If it wants to scroll more than a view-full:
  54.                             ForceRedraw three times;
  55.                         Else if scrolling is unidirectional (the usual case):
  56.                             ScrollRect once with an enlarged rectangle;
  57.                         Else if it is bidirectional:
  58.                             ScrollRect three times.
  59.                         Then update.
  60.  
  61.     When addressed to the secondary scroller:
  62.         -> TSecondaryScroller.ScrollBy
  63.             -> TSecondaryScroller.DoScroll
  64.                     Delegates to TPrimaryScroller
  65.                         -> TPrimaryScroller.ScrollBy (see above)
  66.  
  67. One complication is that resizing (and potentially other activities) can tell
  68. all three scrollers to ScrollTo without redrawing.    If this were allowed to
  69. happen, some state would be altered twice, and the secondary scrollers would
  70. fail to update properly when resized larger after being scrolled to the limit.
  71.  
  72. All such activities bottleneck through SetScrollLimits.  Upon reflection, we realize
  73. that SetScrollLimits has no business affecting any peer scroller.  There is an override
  74. of it in class TSynchScroller to temporarily set an instance variable, fLimiting,
  75. that tells both overrides of DoScroll to exhibit inherited behavior only. (??? there must
  76. be a better way!!!)
  77.  
  78. The unit is not very difficult to use.    The following comments from
  79. USynchScroller.p illustrate the changes one would make to a typical program.
  80.  
  81.      How to use this unit:
  82.         In the .r file resource 'view':
  83.             'WIND', 'SCLP',
  84.             { 17, 32 }, { 200, 300 }, sizeRelSuperView, sizeRelSuperView, shown, enabled,
  85.             Scroller {
  86.                 "TPrimaryScroller",
  87.                 VertScrollBar, HorzScrollBar,
  88.                 0, 0, 16, 16,
  89.                 VertConstrain, HorzConstrain,
  90.                 {-16, -16, 0, 0 }},                 // offset more to make bars even longer
  91.  
  92.             'WIND', 'SCLV',
  93.             { 0, 32 }, { 17, 300 }, sizeFixed, sizeRelSuperView, shown, enabled,
  94.             Scroller {
  95.                 "TSecondaryScroller",
  96.                 noVertScrollBar, noHorzScrollBar,
  97.                 0, 0, 16, 0,
  98.                 noVertConstrain, noHorzConstrain,
  99.                 noInset },
  100.  
  101.             'WIND', 'SCLH',
  102.             { 17, 0 }, { 200, 32 }, sizeRelSuperView, sizeFixed, shown, enabled,
  103.             Scroller {
  104.                 "TSecondaryScroller",
  105.                 noVertScrollBar, noHorzScrollBar,
  106.                 0, 0, 0, 16,
  107.                 noVertConstrain, noHorzConstrain,
  108.                 noInset },
  109.         In the U--.p file:
  110.             USES …, USynchScroller
  111.         In the U--.inc1.p file DoMakeViews:
  112.             VAR
  113.                 aMainScroller:        TPrimaryScroller;
  114.                 aLeftScroller:        TSecondaryScroller;
  115.                 aTopScroller:        TSecondaryScroller;
  116.             …
  117.             aMainScroller := TPrimaryScroller(aMainView.GetScroller(TRUE));
  118.             aLeftScroller := TSecondaryScroller(aLeftView.GetScroller(TRUE));
  119.             aTopScroller  := TSecondaryScroller(aTopView.GetScroller(TRUE));
  120.             aMainScroller.Controls(aLeftScroller, aTopScroller);
  121.         In the M--.p file:
  122.             USES …, USynchScroller
  123.             …
  124.             InitUSynchScroller;
  125.         Code is generated in the following code segments:
  126.             AInit
  127.             ARes
  128.             AFields
  129. *)
  130. {[f+]}
  131. UNIT USynchScroller;
  132.  
  133.     INTERFACE
  134.  
  135.         USES
  136.             { • MacApp }
  137.             UMacApp;
  138.  
  139.             { • Building Blocks }
  140.  
  141.             { • Required for this unit's interface }
  142.  
  143.             { • Implementation Use }
  144.  
  145.         CONST
  146.             kVDependent         = 1;                    { Dependent scroller is dependent on
  147.                                                          vertical translation }
  148.             kNotVDependent        = 0;                    { Dependent scroller is NOT dependent on
  149.                                                          vertical translation }
  150.             kHDependent         = 1;                    { Dependent scroller is dependent on
  151.                                                          horizontal translation }
  152.             kNotHDependent        = 0;                    { Dependent scroller is NOT dependent on
  153.                                                          horizontal translation }
  154.  
  155.         TYPE
  156.  
  157.             TSynchScroller        = OBJECT (TScroller)    { The common superclass of TPrimaryScroller
  158.                                                          and TSecondaryScroller. Merely overrides
  159.                                                          SetScrollLimits to assure that resizing is
  160.                                                          reliable. }
  161.  
  162.                 fLimiting:            BOOLEAN;            { Pushed and popped by SetScrollLimits to
  163.                                                          tell DoScroll not to affect peer scrollers
  164.                                                          }
  165.  
  166.                 PROCEDURE TSynchScroller.IRes(itsDocument: TDocument;
  167.                                               itsSuperview: TView;
  168.                                               VAR itsParams: Ptr); OVERRIDE;
  169.                 { Initialize from templates }
  170.  
  171.                 PROCEDURE TSynchScroller.SetScrollLimits(scrollLimit: VPoint;
  172.                                                          drawScrollBars: BOOLEAN); OVERRIDE;
  173.                 { Avoid affecting any peer scroller }
  174.  
  175.                 PROCEDURE TSynchScroller.Fields(PROCEDURE
  176.                                                 DoToField(fieldName: Str255;
  177.                                                           fieldAddr: Ptr;
  178.                                                           fieldType: INTEGER)); OVERRIDE;
  179.                 END;                                    { TSynchScroller }
  180.  
  181. {--------------------------------------------------------------------------------------------------}
  182.             {$IFC qHasForward}
  183.             TSecondaryScroller    = OBJECT;    FORWARD;
  184.             {$EndC}
  185.  
  186.             TPrimaryScroller    = OBJECT (TSynchScroller) { A TPrimaryScroller has a list of
  187.                                                            secondary scrollers (if non-NIL): When
  188.                                                            it scrolls it makes the scrollers on the
  189.                                                            list scroll too in the very same
  190.                                                            ScrollRect toolbox call if possible. If
  191.                                                            some of the secondary scrollers can't be
  192.                                                            scrolled in the same ScrollRect call
  193.                                                            because they only scroll in one
  194.                                                            direction then they will be scrolled
  195.                                                            separately as necessary. }
  196.  
  197.                 fSecondaryScrollers: TList;             { The list of secondary scrollers, if any }
  198.  
  199.                 PROCEDURE TPrimaryScroller.IRes(itsDocument: TDocument;
  200.                                                 itsSuperview: TView;
  201.                                                 VAR itsParams: Ptr); OVERRIDE;
  202.                 { Initialize from templates }
  203.  
  204.                 PROCEDURE TPrimaryScroller.Free; OVERRIDE;
  205.                 { Frees its list }
  206.  
  207.                 PROCEDURE TPrimaryScroller.AddSecondaryScroller(itsSecondaryScroller:
  208.                                                                 TSecondaryScroller;
  209.                                                                 itsHDependency,
  210.                                                                 itsVDependency: VCoordinate);
  211.                 { Become associated with the secondary scroller(s). The V and H dependencies could
  212.                 someday be scale factors but for now are kVDependent and kHDependent for now. }
  213.  
  214.                 PROCEDURE TPrimaryScroller.RemoveSecondaryScroller(itsSecondaryScroller:
  215.                                                                    TSecondaryScroller);
  216.                 { Remove the secondary scroller. }
  217.  
  218.                 PROCEDURE TPrimaryScroller.DoScroll(delta: VPoint;
  219.                                                     redraw: BOOLEAN); OVERRIDE;
  220.                 { Assure that fTranslation is always updated in the secondary scrollers }
  221.  
  222.                 PROCEDURE TPrimaryScroller.ScrollDraw(delta: VPoint;
  223.                                                       invalidate: BOOLEAN); OVERRIDE;
  224.                 { Scroll the secondary scrollers as well (unless called via SetScrollLimits) }
  225.  
  226.                 PROCEDURE TPrimaryScroller.Fields(PROCEDURE
  227.                                                   DoToField(fieldName: Str255;
  228.                                                             fieldAddr: Ptr;
  229.                                                             fieldType: INTEGER)); OVERRIDE;
  230.  
  231.                 END;                                    { TPrimaryScroller }
  232.  
  233. {--------------------------------------------------------------------------------------------------}
  234.             TSecondaryScroller    = OBJECT (TSynchScroller) { A TSecondaryScroller is controlled by a
  235.                                                            TPrimaryScroller (see above). When it is
  236.                                                            told to scroll, it delegates the job to
  237.                                                            the TPrimaryScroller. Constraints (none
  238.                                                            are checked by this unit at this time):
  239.                                                            1. It and its subview must have the same
  240.                                                            length in the desired synch-scroll
  241.                                                            directions. 2. Commands for dragging
  242.                                                            within it must have it as their
  243.                                                            fScroller. 3. No scroll bars! }
  244.  
  245.                 fPrimaryScroller:    TPrimaryScroller;    { the primary scroller }
  246.                 fDeltaFactor:        Point;                { kVDependent and kHDependent (or not) }
  247.  
  248.                 PROCEDURE TSecondaryScroller.DoScroll(delta: VPoint;
  249.                                                       redraw: BOOLEAN); OVERRIDE;
  250.                 { Polarize and delegate scroll attempts to the primary scroller
  251.                   (unless called via SetScrollLimits) }
  252.  
  253.                 PROCEDURE TSecondaryScroller.Fields(PROCEDURE
  254.                                                     DoToField(fieldName: Str255;
  255.                                                               fieldAddr: Ptr;
  256.                                                               fieldType: INTEGER)); OVERRIDE;
  257.  
  258.                 END;                                    { TSecondaryScroller }
  259.  
  260. {--------------------------------------------------------------------------------------------------}
  261.  
  262.         PROCEDURE InitUSynchScroller;
  263.         { Call from your Mxxx.p to perform required initialization. }
  264.  
  265.     IMPLEMENTATION
  266.  
  267.         {$I USynchScroller.inc1.p}
  268.  
  269. END.
  270.