3. "6F^5P:H r^#<#<H;
;File SBarCDef.TEXT
;--------------------------------------------------------------------------
;
;  Standard ScrollBar Dial Definition Procedure for the
;       MacIntosh Control Manager
;
;  written by Andy Hertzfeld  August, 1982
;
;  (c) 1982 by Apple Computer, Inc.  All rights reserved.
;
;    This file contains the control definition procedure
;    that defines scrollBar-type dials.
;
;  Modification History:
;
;    29-Aug-82  AJH  Added "255" hiliting, non-rectangular indicators
;                    to ScrollBarProc
;    31-Aug-82  AJH  Added hysterisis to scrollBar, ronding to value calculations
;    19-Sep-82  AJH  Re-arranged ScrollBar proc, removed DragThumb
;    03-Oct-82  AJH  Fixed bug in scrollBar positioning -- wasn't ctl relative
;    10-Oct-82  AJH  Converted for QuickDraw Trap Interface
;    17-Oct-82  AJH  Made controlProcs preserve A1
;    07-Nov-82  AJH  Made wide scrollBars look better
;    11-Nov-82  AJH  fixed thumb scaling problem in CalcIBox (subtract min)
;    14-Nov-82  AJH  removed box in arrowBits
;    16-Nov-82  AJH  Made branch tables offset based
;    28-Dec-82  AJH  Put scrollBar definition proc in its own file
;    30-Dec-82  AJH  Changed hystersis for thumbDrag to 24 pixels
;    30-Jul-83  SC   Variant 1 for microsoft - no grey or elevator (Yuck)
;    04-Sep-83  AJH  Made it respond to message 8 (just a stub)
;    08-Oct-83  AJH  Changed rounding to fix "off by 1" bug
;    10-Nov-83  AJH  Changed disabling -- don't fill with gray
;    11-Nov-83  AJH  Made it redraw all if disabled
;    27-Dec-83  AJH  Made min=max act disabled; added "254" hiliting
;    13-Apr-84  SC   Replaced _EraseRgn with _FillRgn,white
;
;----------------------------------------------------------------------------

                .INCLUDE  TlAsm/SYSEQU.TEXT
                .INCLUDE  TlAsm/SYSMACS.TEXT
                .INCLUDE  TlAsm/GRAFEQU.TEXT
                .INCLUDE  TlAsm/GRAFTYPES.TEXT
                .INCLUDE  TlAsm/TOOLEQU.TEXT
                .INCLUDE  TlAsm/RESEQU.TEXT
                .INCLUDE  TlAsm/QuickMacs.TEXT
                .INCLUDE  TlAsm/ToolMacs.TEXT
;
                .PROC     SDEF,0
;
; FUNCTION ScrollBarProc( theControl: ControlHandle;
;                         message:    INTEGER;
;                         param:      LongInt): LongInt;
;
;  Here is the dispatch table for the scrollBar definition procedure, which implements
;  semi-Lisa style scrollBar type controls for the Mac toolBox.  It shares a common
;  dispatcher with the pushButton proc (see above)
;
;
SavePen         .EQU    -20
IndicatorRect   .EQU    -30
;
                BRA.S    @0

                .WORD    0
                .ASCII   'CDEF'
                .WORD    1
                .WORD    1                      ;version #
@0
                LINK    A6,#-30                 ;set up a stack frame to address parameters
                MOVEM.L D3-D6/A1-A4,-(SP)       ;save work registers
;
; save the penState and set it our way
;
                PEA     SavePen(A6)             ;push pointer to savePenState
                _GetPenState                    ;remember current penState
                _PenNormal                      ;set the pen the way we want it
;
; fetch the parameters into registers
;
                LEA     8(A6),A0                ;get ptr to first parameter
                MOVE.L  (A0)+,D3                ;get param in D3
                MOVE.W  (A0)+,D0                ;get message
                MOVE.L  (A0)+,A3                ;get the control handle
                MOVE.W  (A0)+,D6                ;get selection index
                CLR.L   (A0)                    ;clear out function result
                MOVE.L  (A3),A0                 ;get control pointer in A0
;
; case out on the message number
;
                ADD     D0,D0                   ;double for word index
                LEA     GoScrollBar,A1          ;get table address
                ADD     0(A1,D0),A1             ;compute dispatch address
                JSR     (A1)                    ;dispatch to appropriate routine
;
; restore original pen state
;
                PEA     SavePen(A6)             ;push savePenState
                _SetPenState                    ;restore original pen state
;
; we're done -- restore registers and return to caller
;
                MOVEM.L (SP)+,D3-D6/A1-A4       ;restore work registers
                UNLK    A6                      ;unlink stack frame
TenBytExit      MOVE.L  (SP)+,A0                ;get return address
                ADD     #12,SP                  ;strip parameters
                JMP     (A0)                    ;return to caller

GoScrollBar
                .WORD   DrawSBar-GoScrollBar    ;draw is message 0
                .WORD   HitSBar-GoScrollBar     ;hit test is message 1
                .WORD   CalcSBar-GoScrollBar    ;calc regions is message 2
                .WORD   InitSBar-GoScrollBar    ;allocate indicator region (3)
                .WORD   DispSBar-GoScrollBar    ;de-allocate indicator region (4)
                .WORD   MoveSBar-GoScrollBar    ;message 5 is move indicator call (5)
                .WORD   ThumbSBar-GoScrollBar   ;message 6 is thumb dragging
                .WORD   StubSBar-GoScrollBar    ;no custom dragging (7)
                .WORD   StubSBar-GoScrollBar    ;no built-in action proc
;
;  16 wide by 16 high little bitMaps used for scrollBar arrows
;
;   (the comments as to which are left/right or up/down may lie)
;

;
; Left Arrow BitMap
;
LArrowData
                .WORD   $FFFF,$8081,$80C1,$80A1,$8F91,$8809,$8805,$8803
                .WORD   $8805,$8809,$8F91,$80A1,$80C1,$8081,$8001,$FFFF
LArrowMask
                .WORD   $FFFF,$8081,$80C1,$80E1,$8FF1,$8FF9,$8FFD,$8FFF
                .WORD   $8FFD,$8FF9,$8FF1,$80E1,$80C1,$8081,$8001,$FFFF

;
;  Right Arrow BitMap
;
RArrowData
                .WORD   $FFFF,$8101,$8301,$8501,$89F1,$9011,$A011,$C011
                .WORD   $A011,$9011,$89F1,$8501,$8301,$8101,$8001,$FFFF
RArrowMask
                .WORD   $FFFF,$8101,$8301,$8701,$8FF1,$9FF1,$BFF1,$FFF1
                .WORD   $BFF1,$9FF1,$8FF1,$8701,$8301,$8101,$8001,$FFFF

;
; Up Arrow BitMap
;
UArrowData
                .WORD   $FFFF,$8001,$8001,$8FE1,$8821,$8821,$8821,$F83D
                .WORD   $A009,$9011,$8821,$8441,$8281,$8101,$8001,$FFFF
UArrowMask
                .WORD   $FFFF,$8001,$8001,$8FE1,$8FE1,$8FE1,$8FE1,$FFFD
                .WORD   $BFF9,$9FF1,$8FE1,$87C1,$8381,$8101,$8001,$FFFF
;
; Down Arrow BitMap
;
DArrowData
                .WORD   $FFFF,$8001,$8101,$8281,$8441,$8821,$9011,$A009
                .WORD   $F83D,$8821,$8821,$8821,$8FE1,$8001,$8001,$FFFF
DArrowMask
                .WORD   $FFFF,$8001,$8101,$8381,$87C1,$8FE1,$9FF1,$BFF9
                .WORD   $FFFD,$8FE1,$8FE1,$8FE1,$8FE1,$8001,$8001,$FFFF
;
; DrawSBar draws a scroll bar as specified by the controlHandle in A3. D3 has the
; desired "hilite" area code.
;
DrawSBar
;
; Figure out if the scroll bar is horizontal or vertical and handle each
; case separately. see if its more horizontal or vertical -- A0 points to the
; rect to be tested.  D0 returns 0 to select vertical and two to select horizontal.
; After we know which axis, draw the arrows.
;
                TST.B   ContrlVis(A0)           ;is it visible?
                BEQ     StubSBar                ;if not, don't draw

; if it was disabled, draw the whole thing

                CMP.B   #$FF,D3                 ;disabled part code?
                BNE.S   @0                      ;if not, skip
                MOVEQ   #0,D3                   ;if so, draw all
@0
                MOVE.B  ContrlHilite(A0),D4     ;get current hilite in register
                BSR     GetTCtlRect             ;copy the control rect into tempRect
                BSR     TestHV                  ;get horizontal/vertical index in D0
;
; adjust for 1st arrow (if we're supposed to)
;
                MOVE.W  Top(A1,D0),D1           ;get vertical coordinate
                ADD     D2,D1                   ;compute bottom
                MOVE.W  D1,Bottom(A1,D0)        ;update bottom
                LEA     RArrowData,A1           ;point to right arrow bitMap
                MOVEQ   #inUpButton,D1          ;signal 1st arrow
;
                MOVEM   D0/D2,-(SP)             ;remember hv selector
;
                BSR.S   ShouldIDraw             ;test hilite to see if we should draw
                BNE.S   SkipUp
                BSR     DrawArrowBox            ;draw the arrow box
;
; now do the other arrow
;
SkipUp
                BSR     GetTCtlRect             ;copy bounding rect into tempRect
                MOVEM   (SP)+,D0/D2             ;restore hv selector
;
; adjust rect for 2nd arrow
;
                MOVE    Bottom(A1,D0),D1        ;get bottom coordinate
                SUB     D2,D1                   ;compute top
                MOVE    D1,Top(A1,D0)           ;adjust box top
                LEA     LArrowData,A1           ;point to 1st set of bitMaps
                MOVEQ   #inDownButton,D1        ;signal in 2nd arrow
;
                BSR.S   ShouldIDraw             ;dont't draw if we done have to
                BNE.S   SkipDown
                BSR     DrawArrowBox            ;draw the arrow box

;
; paint the body of the scrollBar light gray
;
SkipDown
;
                CMP     #1,D6                   ;flavor one has no grey
                BEQ     FrameCtl

                MOVE.W  #inThumb,D1             ;get thumb part code
                BSR.S   ShouldIDraw             ;draw it?
                BNE     FrameCtl                ;if not, skip

                ;CMP     #inThumb,D3             ;if we're just drawing, just remove it
                ;BEQ.S   GrayIndicator           ;dont do the whole rect

                BSR     GetTCtlRect             ;get control bounding rectangle
                MOVE.L  A1,-(SP)                ;push tempRect
                BSR     GetLtGray               ;get pointer to light gray pattern
                MOVE.L  A0,-(SP)                ;push it
;
                BSR.S   IsDisabled              ;is it disabled?
                BNE.S   @0                      ;if not, skip

                MOVE.L  (A5),A0                 ;get grafGlobals
                LEA     White(A0),A0            ;get address of white pattern
                MOVE.L  A0,(SP)                 ;use it
@0
                LEA     TempRect,A1             ;get tempRect pointer back
                MOVE.L  A1,A0                   ;put in A0 for TestHV
                BSR.S   TestHV                  ;get h/v index
                SWAP    D2                      ;get width in high part
                MOVE.W  #1,D2                   ;get 1 in low part
                TST.W   D0                      ;which dimension?
                BEQ.S   @1                      ;skip correction if vertical

                SWAP    D2
;
@1              MOVE.L  A1,-(SP)                ;push a pointer to the rectangle
                MOVE.L  D2,-(SP)                ;push inset factor
;
                _InsetRect                      ;inset it appropriately
                _FillRect                       ;paint the body gray
                BRA.S   DoIndicator             ;go plot the indicator
;
; Utility ShouldIDraw -- to test when to skip drawing a part of the scrollBar.
; On entry, D3 has parameter indicating part that needs drawing while D1 holds
; the part we are about to draw.  If D3 is zero, always draw it.  Otherwise,
; draw only if it matches.  Returning 0 in the Z-flag means you should draw
;
ShouldIDraw
                TST     D3                      ;examine the parameter
                BEQ.S   StubSBar                ;its zero so don't test further
                CMP     D1,D3                   ;the right part
StubSBar        RTS                             ;the z-flag has the answer

; IsDisabled is a utility to check to see if a scrollBar is disabled or not.
; It returns with the z-flag set if it is disabled

IsDisabled
                MOVE.L  (A3),A0                 ;get sBar pointer
                MOVE.B  ContrlHilite(A0),D0     ;get the hilite parameter

                ADDQ.B  #1,D0                   ;was it 255?
                BEQ.S   @0                      ;if so, its disabled
                ADDQ.B  #1,D0                   ;how about 254?
                BEQ.S   @0                      ;if so, its disabled also

                MOVE.W  ContrlMin(A0),D0        ;get the min
                CMP.W   ContrlMax(A0),D0        ;same as the max?
 @0
                RTS                             ;return to caller with z-flag result

;
;  We're just changing the indicator so gray it out.
;
;GrayIndicator
                ;BSR.S   IsDisabled
                ;BEQ.S   FrameCtl                ;if so, skip

                ;MOVE.L  ContrlData(A0),-(SP)    ;push handle to indicator region
                ;BSR     GetLtGray               ;get pointer to light gray
                ;MOVE.L  A0,-(SP)                ;push light gray
                ;_FillRgn                        ;erase the indicator
;
; Check the hilite state.  If the control is inactive (hilite = 255), don't draw
; the indicator at all.
;
DoIndicator
                BSR     CalcIBox                ;calculate the indicator box
                BSR.S   IsDisabled
                BEQ.S   FrameCtl                ;if so, skip

                MOVE.L  ContrlData(A0),-(SP)    ;push indicator region handle
                MOVE.L  (SP),-(SP)              ;we need it again
                MOVE.L  GrafGlobals(A5),A0      ; our erase rect
                PEA     white(A0)
                _FillRgn                        ;paint it white
                _FrameRgn                       ;and frame it
;
; frame the whole rect
;
FrameCtl
                MOVE.L  (A3),A0
                PEA     ContrlRect(A0)          ;push pointer to scrollBar rect
                _FrameRect                      ;frame it
;
; all done drawing the scroll bar
;
                RTS

;
; TestHV is a utility that determines if the rectangle pointed to by A0 is more horizontal
; or vertical.  Return 0 in D0 if its more vertical and 2 if its more horizontal.
; This routine trashes D1.  The result is also reflected in the condition code.
; It also returns the width/height of the minor dimension in D2.
;
TestHV
                MOVE    Bottom(A0),D0
                SUB     Top(A0),D0              ;get height
                MOVE    Right(A0),D1
                SUB     Left(A0),D1             ;get width

                CMP     D0,D1                   ;compare width and height
                BGT.S   @1                      ;branch it width is greater

                MOVE    D1,D2                   ;horizontal in D2
                MOVEQ   #0,D0                   ;signal its vertical
                RTS

@1              MOVE    D0,D2                   ;vertical in D2
                MOVEQ   #2,D0                   ;signal its horizontal
                RTS
;
;  DrawArrowBox is a routine that clears and frames an arrow box and then blits
;  across the appropriate arrow (looks at hilite state).  On entry, TempRect has the
;  box for the arrow, D0 has h/v selector, D1 has left/right selector,A1 points to the
;  arrow bitMap, A3 has the control handle.
;
DrawArrowBox
                MOVE.L  (A3),A0                 ;get the control pointer
                CMP.B   ContrlHilite(A0),D1     ;should it be hilited?
                BNE.S   @1                      ;if not, skip
                ADD     #32,A1                  ;if so, bump to hilite mask
;
; adjust bitMap for vertical or horizontal arrows
;
@1              TST     D0
                BNE.S   @2
                ADD     #128,A1                 ;bump to horizontal
;
; plot the arrow
;
@2              CLR     D0                      ;mode is srcCopy
                BSR.S   PlotSymbol              ;plot the bitmap in the tempRect box
;
; Now frame the box and we're done!
;
                PEA     TempRect                ;push the rectangle
                _FrameRect                      ;frame it and we're done
SBarStub
                RTS
;
;  PlotSymbol -- plot the little 16 by 16 symbol bitmap pointed to by A1 into the rectangle
;  pointed held in TempRect. D0 holds the mode.
;
PlotSymbol
                LEA     IconBitMap,A0           ;get pointer to source bitmap
                MOVE.L  A1,(A0)+                ;update base address of bitMap
                MOVE    #2,(A0)+                ;update rowBytes
                CLR.L   (A0)+                   ;topLeft is zero, zero
                MOVE.L  #$00100010,(A0)         ;adjust boundsRect
;
; push parameters for CopyBits call to transfer arrow bitMap
;
                PEA     IconBitMap              ;push pointer source bitmap
                MOVE.L  (SP),A0                 ;remember in A0, too
                MOVE.L  LGLOBALS(A5),A1         ;get lisaGraf global baseaddress
                MOVE.L  THEPORT(A1),A1          ;get thePort
                PEA     PORTBITS(A1)            ;that's the destination bitmap
;
                PEA     BOUNDS(A0)              ;boundsRect of bitmap is source
                PEA     TempRect                ;tempRect is the destination
                MOVE.W  D0,-(SP)                ;theMode is in D0
                CLR.L   -(SP)                   ;no mask region
;
; transfer the bitMap (stretching as necessary...)
;
                _CopyBits                       ;let Bill stretch those bits
                RTS                             ;return to caller
;
; CalcIBox is the crucial routine that computes the position of the top/left of the
; thumb by scaling the control's value according to its range and the screen area.
; Return the rectangle in IndicatorRect(A6).  It expects that A3 will hold the
; control handle as usual
;
CalcIBox
                MOVE    D3,-(SP)                ;preserve D3
                LEA     IndicatorRect(A6),A1    ;get address of indicator rectangle
                BSR.S   GetCtlRect              ;first set it to control bounding rect
;
                MOVEQ   #0,D1                   ;clear out high part of D1
                MOVE.L  (A3),A0                 ;get pointer to control
                LEA     ContrlRect(A0),A0       ;get pointer to the bounding rectangle
                BSR.S   TestHV                  ;get h/V selector index in D0
                MOVE    D2,D3                   ;keep minor dimension in D3
;
; compute control screen area in relevant dimension
;
                MOVE    Bottom(A0,D0),D1        ;get logical "bottom"
                SUB     Top(A0,D0),D1           ;compute "height"
                SUB     D2,D1                   ;discount arrow box
                SUB     D2,D1                   ;discount other one, too
                SUB     D2,D1                   ;and the indicator
;
; compute "screenSize times value"
;
                MOVE.L  (A3),A0                 ;get control pointer
                MOVE.W  ContrlValue(A0),D2      ;get current value
                SUB.W   ContrlMin(A0),D2        ;get delta from min
                MULU    D2,D1                   ;compute value*screensize
;
; compute size of logical space
;
                MOVE    ContrlMax(A0),D2        ;get max
                SUB     ContrlMin(A0),D2        ;compute size of space
                BEQ.S   Scale0                  ;dont divide by 0
;
; perform the scaling
;
                DIVU    D2,D1                   ;compute where iBox should go
                BSR     RoundOff                ;round off D1
                ADD     D3,D1                   ;skip over arrow box
;
; update indicator rect to correct position
;
UpdateIRect
                LEA     IndicatorRect(A6),A1    ;get pointer to rect
                ADD     Top(A1,D0),D1           ;compute the logical "top"
                MOVE    D1,Top(A1,D0)           ;update it
                ADD     D3,D1                   ;bump to "bottom"
                MOVE    D1,Bottom(A1,D0)        ;update "bottom"
;
                EOR     #2,D0                   ;flip to minor dimension
                ADDQ    #1,Top(A1,D0)           ;inset logical "left"
                SUBQ    #1,Bottom(A1,D0)        ;inset logical "right"
;
; set up the indicator region
;
                MOVE.L  ContrlData(A0),-(SP)    ;push indicator region handle
                MOVE.L  A1,-(SP)                ;push rect ptr
                _RectRgn                        ;make a rectangular region
;
CalcIDone       MOVE    (SP)+,D3                ;restore D3
                RTS
;
; if min = max, pin at top
;
Scale0          MOVE    D3,D1
                BRA.S   UpdateIRect
;
; GetCtlRect is a code saving utility that copies the bounding rectangle of the control
; whose handle is in A3 into the rectangle pointed to by A1.  This routine blows
; A0 but preserves A1. GetTCtlRect is an alternative entry used to save code
;
GetTCtlRect     LEA     TempRect,A1
GetCtlRect      MOVE.L  (A3),A0                 ;get pointer to control
                LEA     ContrlRect(A0),A0       ;get pointer to bounding rect
                MOVE.L  (A0),(A1)               ;copy topLeft
                MOVE.L  4(A0),4(A1)             ;copy botRight
NoSBarHit
                RTS
;
; HitSBar is the hit test routine for the scroll bar definition routine.  It classifies
; the position of the mouse passed in D3
;
HitSBar
                CMP.B   #254,ContrlHilite(A0)   ;254 hilited?
                BEQ.S   Return254

                BSR     IsDisabled              ;is it otherwise disabled?
                BEQ.S   NoSBarHit               ;if so, return 0

                LEA     ContrlRect(A0),A4       ;keep rect pointer in A4
                CLR.W   -(SP)                   ;make room for function result
                MOVE.L  D3,-(SP)                ;push the point
                MOVE.L  A4,-(SP)                ;push address of rect
                _PtInRect                       ;in the rectangle?
                TST.B   (SP)+                   ;examine result
                BEQ.S   NoSBarHit               ;if not, we're done
;
; its in the rect, so classify if in upButton,downButton,pageUp,pageDown or thumb
;
                BSR.S   NormalizePt             ;swap relevant coordinate into low part
;                                               ;and set up D0,D2
; see if its in the top button
;
@1              MOVE    D3,D1                   ;get copy of mousePoint
                SUB     0(A4,D0),D1             ;subtract rectangle top
                CMP     D2,D1                   ;is it within width of the top?
                BGT.S   @2                      ;it not, go check bottom
                MOVEQ   #inUpButton,D0          ;classify it
                BRA.S   UpdateResult            ;all done
;
; see if its in the bottom button
;
@2              MOVE    4(A4,D0),D1             ;get bottom
                SUB     D3,D1                   ;get distance from bottom
                CMP     D2,D1                   ;is it in it?
                BGT.S   CheckInd                ;if not, go check indicator
;
                MOVEQ   #inDownButton,D0
UpdateResult
                MOVE    D0,22(A6)               ;return result
                RTS
Return254
                MOVE    #254,D0
                BRA.S   UpdateResult
;
; its not in either button so it must be the thumb or one of the page areas.  Check
; for the thumb first
;
CheckInd
                CMP      #1,D6                  ; for flavor one don't test
                BEQ.S    NoSBarHit

                BSR     CalcIBox                ;calculate the indicator rectangle
                BSR.S   NormalizePt             ;restore back to normal point
                CLR.W   -(SP)                   ;make space for boolean result
                MOVE.L  D3,-(SP)                ;push the point
                MOVE.L  (A3),A0
                MOVE.L  ContrlData(A0),-(SP)    ;push the indicator region
                _PtInRgn                        ;is the mouse in the indicator?
                TST.B   (SP)+                   ;(..the suspense builds...)
                BEQ.S   CheckPage               ;branch if its not in the indicator
;
; its in the thumb so report that to the application
;
                MOVE    #inThumb,D0             ;get result
                BRA.S   UpdateResult            ;all done -- go update result

;
; it must be in one of the two page areas.  Determine which one by looking at the
; midPoint of the indicator's bounding rectangle.
;
CheckPage
                BSR.S   NormalizePt             ;normalize (get interesting low word)
                MOVE.L  (A3),A0                 ;get control pointer
                MOVE.L  ContrlData(A0),A0       ;get region handle
                MOVE.L  (A0),A0                 ;get region pointer
                LEA     RgnBBox(A0),A0          ;point to the region bounding box
;
; determine midpoint
;
                MOVE    Bottom(A0,D0),D1        ;get logical bottom
                SUB     Top(A0,D0),D1           ;get logical height
                LSR     #1,D1                   ;divide by 2
                ADD     Top(A0,D0),D1           ;add to get the midpoint
;
; at this point, D1 has the midpoint in the important dimension.  Compare with the
; mouse point to decide if its page up or down.
;
                CMP     D1,D3                   ;compare mousePt with midPoint
                BLT.S   PageItUp                ;if above its the logical "top"
                MOVEQ   #inPageDown,D0          ;set result code
                BRA.S   UpdateResult            ;all done -- go update result
PageItUp        MOVEQ   #inPageUp,D0            ;set result code
                BRA.S   updateResult            ;all done
;
; NormalizePt takes a rect pointer in A4 and a point in D3 and swaps the points
; coordinates according to the relevant dimensions
;
NormalizePt
                MOVE.L  A4,A0                   ;get rect pointer in A0
                BSR     TestHV                  ;get horizontal vertical offset
                BNE.S   @1                      ;if horizontal, skip
                SWAP    D3                      ;its vertical so get y in low part
@1              RTS                             ;all done

;
; CalcSBar returns the bounding region of the scroll bar.  D3 holds the region parameter.
; If the high bit of D3 is set, return the indicator region, other return the entire
; bounding region
;
CalcSBar
                TST.L   D3                      ;indicator or body?
                BMI.S   GetIndRgn               ;if negative, go get indicator
                MOVE.L  D3,-(SP)                ;push the region handle
                PEA     ContrlRect(A0)          ;push rectangle pointer
                _RectRgn                        ;return a rectangular region
                RTS                             ;all done!
;
; the indicator region was requested so copy the one in the dataHandle
;
GetIndRgn
                BSR     CalcIBox                ;calculate indicator region
                MOVE.L  (A3),A0                 ;get pointer to control
                MOVE.L  ContrlData(A0),-(SP)    ;push indicator region
                MOVE.L  D3,-(SP)                ;push result region
                CLR.B   (SP)                    ;clear out high byte
                _CopyRgn                        ;clone the region
;
; set the pattern for dragging
;
                BSR.S   GetLtGray               ;get pointer to light gray
                MOVE.L  (A0)+,DragPattern       ;update the drag pattern
                MOVE.L  (A0),DragPattern+4      ;update the drag pattern
                RTS
;
; GetLtGray is a short utility that get a pointer to a lightGray pattern from
; the resource manager.
;
GetLtGray
               SUBQ     #4,SP                   ;make room for result
               MOVE.W   #SBarPatID,-(SP)        ;push resource ID
               _GetPattern                      ;get the pattern
               MOVE.L    (SP)+,A0               ;get pattern handle
               MOVE.L    (A0),A0                ;get pattern ptr
               RTS

;
;  handle the "position yourself" message by calling figuring out the new value and
;  calling SetCtlValue.  D3 holds the amount to move by.
;
MoveSBar
                MOVE.L  ContrlData(A0),A0       ;get handle of indicator region
                MOVE.L  (A0),A0                 ;get a pointer to it
                LEA     RgnBBox(A0),A4          ;get pointer to the bounding rect
;
; figure out new position by adding topLeft of current position to offset
;
                ADD     Left(A4),D3             ;add the x coordinates
                SWAP    D3                      ;get y in low word
                ADD     Top(A4),D3              ;add the y coordinates
;
; select the relevant dimension and get it into the low word of D3
;
                MOVE.L  (A3),A0                 ;get the control pointer
                LEA     ContrlRect(A0),A0       ;get the bounding rectangle
                BSR     TestHV                  ;get h/v index
                BEQ.S   @1                      ;if its y, we're cool
                SWAP    D3                      ;get x into D3
;
; determine amount of screen area devoted to the scrollBar
;
@1              SUB     Top(A0,D0),D3           ;make size ctl-relative
                SUB     D2,D3                   ;subtract arrow offset
;
                MOVE    Bottom(A0,D0),D1        ;get logical bottom
                SUB     Top(A0,D0),D1           ;compute logical height

                SUB     D2,D1                   ;compute active area
                SUB     D2,D1
                SUB     D2,D1
                MOVE    D1,D2                   ;get answer in D2
;
; compute range of logical values: controlMax - controlMin
;
                MOVE.L  (A3),A0                 ;get control pointer
                MOVE    ContrlMax(A0),D1        ;get max value
                SUB     ContrlMin(A0),D1        ;compute range
;
; compute position*logical range/physical range
;
                MULU    D3,D1                   ;D3 has current position
                DIVU    D2,D1                   ;divide by physical range
                BSR.S   RoundOff                ;round to nearest integer
;
; at this point D1 has the value so set it, after offsetting by the minimum
;
                ADD.W   ContrlMin(A0),D1        ;offset by minimum
                MOVE.L  A3,-(SP)                ;push control handle
                MOVE.W  D1,-(SP)                ;push the new value
                _SetCtlValue                    ;go set the new value
                RTS                             ;all done!
;
; InitSBar gets called when the scroll bar is allocated.  It allocates an empty region
; to use as the indicator region
;
InitSBar        SUBQ    #4,SP
                _NewRgn                         ;get a new region on the stack top
                MOVE.L  (A3),A0                 ;get control pointer
                MOVE.L  (SP)+,ContrlData(A0)    ;remember new region in control data
                RTS
;
; DispSBar de-allocates the region used for the indicator
;
DispSBar        MOVE.L  ContrlData(A0),A0       ;get handle of indicator region
                _DisposHandle                   ;dispose of it
                RTS
;
; Utility RoundOff -- RoundOff the number in D1 to the nearest integer.  The remainder
; from dividing by D2 is in the high part of the word.
;
RoundOff        MOVE.W  D0,-(SP)                ;preserve D0
                MOVE    D2,D0                   ;get old divisor
                LSR     #1,D0                   ;divide by 2
                SWAP    D1                      ;get remainder
                CMP     D0,D1                   ;compare remainder with 1/2 divisor
                BLE.S   TruncateIt              ;if smaller, we're done
                SWAP    D1                      ;get normal D1 back
                ADDQ    #1,D1                   ;round up
;
RoundDone
                MOVE.W  (SP)+,D0                ;restore D0
                RTS
;
;  no need to round up so just truncate it
;
TruncateIt
                SWAP    D1                      ;restore quotient
                BRA.S   RoundDone               ;all done with roundOff

;
; ThumbSBar receives the "drag thumb message for the scroll bar.  On entry, D3 points
; to a structure that contains the starting point, it returns with pointers to
; the bounds and slopRect and the axis parameter
;
; Local Variable Equates
;
BRect           .EQU    0                     ;boundsRect
SRect           .EQU    8                     ;slopRect
TAxis           .EQU    16                     ;axis
;
ThumbSBar
                MOVE.L  D3,A4                   ;keep pointer to parameter block
                MOVE.L  (A4),D3                 ;get the mouse point
;
                LEA     BRect(A4),A2            ;get pointer to boundsRect
                MOVE.L  A2,A1                   ;get pointer in A1
                BSR     GetCtlRect              ;copy control bounds rect
;
                MOVE.L  A2,A0                   ;point to boundsRect
                BSR     TestHV                  ;get h/v selector in D0
                MOVE    D2,-(SP)                ;preserve D2
                SWAP    D2
                MOVE.W  #$FFE8,D2               ;get inset factor (24 pixels hyst)
                MOVE    D0,D4                   ;keep selector in D4
                BEQ.S   @1                      ;if vertical, we're cool
                SWAP    D2                      ;adjust inset factor
                BRA.S   @2
;
@1              SWAP    D3                      ;adjust mouse pt
;
@2              MOVE.L  A2,-(SP)                ;push pointer to rectangle
                MOVE.L  D2,-(SP)                ;push inset factor
                _InsetRect                      ;go inset it
;
; build the slopRect by insetting the boundsRect
;
                LEA     SRect(A4),A0            ;get slopRect pointer
                MOVE.L  (A4),(A0)               ;copy boundsRect into slopRect
                MOVE.L  4(A4),4(A0)             ;copy botRight, too
;
                MOVE.L  #$FF800000,D0           ;get inset factor (assume vertical)
                TST     D4                      ;which dimension
                BEQ.S   @3                      ;if vertical, we're cool
                SWAP    D0
;
@3              MOVE.L  A0,-(SP)                ;push slopRect pointer
                MOVE.L  D0,-(SP)                ;push inset factor
                _InsetRect                      ;inset it
;
; now further adjust the boundsRect depending where the mousePt is relative to the
; indicator box.
;
                MOVE.L  (A3),A0                 ;get control pointer
                MOVE.L  ContrlData(A0),A0       ;get region handle
                MOVE.L  (A0),A0                 ;get region pointer
                SUB     RgnBBox(A0,D4),D3       ;subtract relevant coordinate
                ADD     D3,Top(A2,D4)           ;offset logical top
;
; fix up logical bottom, too
;
                MOVE    (SP)+,D2                ;get back D2
                SUBQ    #1,D2
                SUB     D2,Bottom(A2,D4)
                ADD     D3,Bottom(A2,D4)        ;subtract (15-number) from bottom
;
; now set up axis parameter
;
                LSR     #1,D4                   ;divide by 2
                EOR     #1,D4                   ;flip the sense
                ADDQ    #1,D4                   ;add increment
                MOVE    D4,TAxis(A4)            ;to derive axis parameter
                RTS


               .END
