*******************************************************************************
*
* RoundRect Window
*
* (C)  Copyright Apple Computer, Inc. 1988-1990
* All rights reserved.
*
* Developer Technical Support Apple II Sample Code
*
* by Keith Rollin
*
* This file contains the definition procedure (defProc) for a custom window.
* This window acts like a fairly normal, but limited, window, and has the
* following features:
*
*     - The corners are curved. The radius of the corners can be specified.
*     - It always has a title bar, which always has a solid background color
*       and title in it. The titlebar redraws itself in response to being
*       activated and deactivated.
*     - A GoAway box can optionally be included in the title bar. The zoom
*       box is not drawn or supported.
*     - There are no infobars or frame controls (like scrollbars).
*     - A color table can be provided, or a default color table can be used.
*     - The window can be dragged and grown.
*     - TaskMaster is supported.
*
*******************************************************************************

                    EJECT
*******************************************************************************
*
RRectDefProcData    data
*
* Description:      Equates and variables used by the RoundRect Window defProc.
*
*
*******************************************************************************

; stack/direct page frame. These equates are used to access information that
; is passed to the window DefProc on the stack.


                    DefineStack

OrigD               word                ; saved Direct Page register
OrigB               byte                ; saved Data Bank register
work                long                ; a LONG of workspace
workRgn             long                ; a LONG of workspace
returnAddr          block 3             ; RTL address
param               long                ; operation specific parameter
theWindow           long                ; This is NOT a pointer to the window.
*                                       ; This is a pointer to a window record.
*                                       ; This means that it points to
*                                       ; owNext, not the grafPort part of
*                                       ; a window record!!
operation           word                ; operation to perform
windGlobals         long                ; pointer to handy values
result              long                ; place to store operation result

;
; Window Globals table
;
lineW               equ 0               ; width of vertical lines
titleHeight         equ lineW+2         ; Height of standard title bar
titleYPos           equ titleHeight+2   ; Y offset for title in std. titlebar
closeHeight         equ titleYPos+2     ; height of close icon.
closeWidth          equ closeHeight+2   ; width of close icon.
defWindClr          equ closeWidth+2    ; pointer to default color table
windIconFont        equ defWindClr+4    ; handle to current window icon font
screenMode          equ windIconFont+4  ; TRUE if 640 mode, FALSE if 320
pattern             equ screenMode+2    ; Temporary pattern buffer
callerDPage         equ pattern+32      ; DP of last caller to TaskMaster
callerDataB         equ callerDPage+2   ; DBR of last caller to TaskMaster

;
; NewWindow Parameter list
;
                    DSect 0
wParamID            word                ; should be zero for custom windows
wMe                 long                ; address of customProc
wFrameBits          word                ; flags that determine window type
wPosition           block 8             ; used as portRect for contents
wPlane              long                ; window Plane
wStorage            long                ; storage for the window record
; These 2 are copied in one pass. Keep together and in this order.
wRefCon             long                ; refCon
wContDraw           long                ; routine that draw the contents
; Everything past here is copied after the wFrame field of the Window Record.
wCustom             block 0             ; start of custom information section
wTitle              long                ; pointer to window's title
wColorTable         long                ; pointer to color table
wRV                 word                ; vertical radius of corners
wRH                 word                ; horizontal radius of corners
wEnd                block 0

;
; My extensions for this custom window
;
                    DSect windSize
xowTitle            long                ; pointer to window's title
xowColorPtr         long                ; pointer to our color table (if any)
xowRV               word                ; vertical radius of corners
xowRH               word                ; horizontal radius of corners
xowEnd              block 0

;
; Position of the GoAway box
;
GAX                 equ 10
GAY                 equ 2

;
; Scratch areas
;
contRect            ds 8
strucRect           ds 8
pRect               ds 8

                    end


                    EJECT
*******************************************************************************
*
RRectDefProc        start
*
* Description:      Main Procedure for the RoundRect custom window definition.
*                   This routine creates a suitable environment for us (saves
*                   the old Direct Page and Data Bank registers and makes us
*                   some new ones), calls the appropriate routine based on
*                   the value of 'operation', and returns to the Window
*                   Manager with the Carry bit and Y register set correctly.
*
*
* Inputs:
*                   On entry, the stack contains the following values:
*
*                   -------- previous contents --------
*                   LONG  result        space for result
*                   LONG  windGlobals   pointer to WMgr globals
*                   WORD  operation     operation number to be performed
*                   LONG  theWindow     ptr to window's record
*                   LONG  param         additional parameter for some ops.
*                   3 Bytes             RTL Address
*                         <------------ Stack Pointer
*
* Outputs:          Carry = clear if no error
*                   Carry = set if error, and Y has error number.
*
* External Refs:
*                   Import rrDraw
*                   Import rrHit
*                   Import rrCalcRgns
*                   Import rrNew
*                   Import rrDispose
*                   Import rrGetDrag
*                   Import rrGrowFrame
*                   Import rrRecSize
*                   Import rrPosition
*                   Import rrBehind
*                   Import rrCallDefProc
*
* Entry Points:     NONE
*
*******************************************************************************
                    using RRectDefProcData
wMaxTask            equ 10

; The first thing we do is get a little Direct Page space by using the stack.
; First, push on some scratch space onto the stack, then save the old values
; of the Data Bank Register and the Direct Page Register. Set the Data Bank
; Register to the same value as the Program Bank Register, and then transfer
; the Stack Pointer to the Direct Page Register. This gives us a stack and
; Direct Page that looks like this:
;
; Direct Page location  SIZE  What it is
;                   25  LONG  result
;                   21  LONG  windGlobals
;                   19  WORD  operation
;                   15  LONG  theWindow
;                   11  LONG  param
;                    8  3 Bytes RTL Address
;                    4  LONG  workspace
;                    3  BYTE  old Data Bank Register
;                    1  WORD  old Direct Page Register
;                           <--- stack pointer

                    pha                 ; Push on 8 bytes of workspace.
                    pha
                    pha
                    pha

                    phb                 ; Save the data bank register
                    phd                 ; Save the direct page register

; Set the Data Bank register to the Program Bank register. This allows short
; (2 byte) addressing, as opposed to the 3 byte addressing we would have had
; to use if the Data Bank register were set to some unknown value.

                    phk                 ; Set up my own DBR
                    plb

; Set the direct page to the stack. This lets us use some of the values passed
; to us as 'zero-page' pointers (like theWindow).

                    tsc                 ; Set up my own Direct Page
                    tcd

; Zero out 'result' as default.

                    stz <result         ; zero this out to start with
                    stz <result+2

; Find out which operation to perform, check its range, and, if it is OK,
; convert it to an index into a jump table. Execute the routine.

                    lda <operation
                    cmp #wMaxTask+1
                    bcs OutOfRange

                    asl a
                    tax
                    jsr (opTable,x)

; The operation has been carried out. Strip the parameters off of the stack
; and move the return address up, making sure to leave the 'result'. Gotta be
; careful to preserve the carry flag here!!!

OutOfRange          lda <returnAddr     ; move the return address up
                    sta <result-3
                    lda <returnAddr+1
                    sta <result-2

                    tsc                 ; get the stack ptr so we can change it

                    pld                 ; restore the DP and DBR
                    plb

                    php                 ; save the state of the carry
                    clc                 ; fudge the stack pointer
                    adc #result-4
                    plp                 ; restore the carry state
                    tcs                 ; point the stack pointer to the return
*                                       ; address we moved up

                    rtl                 ; back to the window manager

opTable             dc i2'rrDraw'       ; Draw the specified part
                    dc i2'rrHit'        ; determine where we hit
                    dc i2'rrCalcRgns'   ; Calculate Struc and Content Regions
                    dc i2'rrNew'        ; Perform initialization
                    dc i2'rrDispose'    ; Close window
                    dc i2'rrGetDrag'    ; Dragging to be done
                    dc i2'rrGrowFrame'  ; Grow the frame
                    dc i2'rrRecSize'    ; Return our window record size
                    dc i2'rrPosition'   ; Return window pos/size
                    dc i2'rrBehind'     ; Return plane placement
                    dc i2'rrCallDefProc'                    ; Perform special stuff

                    end

                    EJECT
*******************************************************************************
*
rrDraw              start
*
* Description:      Draw the specified part of the window.
*
* We draw the window frame (part $0000) in the following way:
*
*   1. Save various QuickDraw states that we will be changing.
*   2. Set the pen to normal.
*   3. Get the rectangle of our structure region.
*   4. Get a pointer to the color table we'll be using.
*   5. Set the color of the title bar (background). This changes
*      depending on whether the window is active or not.
*   6. Draw the title bar with PaintRect.
*   7. Set the color to the outline color.
*   8. Draw the main part of the frame with FrameRRect.
*   9. Draw the line that divides the title bar from the content region.
*  10. Calculate and position the pen for the string title.
*  11. Set the color for the title. Again, this changes depending on
*      whether the window is active or not.
*  12. If the window is active, call the standalone routine that draws
*      the close box (part $0001).
*  13. Restore the QuickDraw state we saved and return.
*
*
* Inputs:           param  = specification of part to draw:
*
*                        0 = draw the entire window
*                        1 = draw the go-away region
*                        2 = draw the zoom region
*                        3 = draw the info bar
*
*                   If the high bit of param is set, then draw the item in
*                   its highlighted state. Note: to determine whether to draw
*                   a window titlebar in its active or inactive state, look
*                   at the fHilite flag in the window record.
*
* Outputs:          result = zero
*                   carry  = clear
*
* External Refs:    NONE
*
* Entry Points:
*                   entry drawFrame     ; called by rrSetxxxx routines when a
*                                       ; field is changed.
*
*******************************************************************************
                    using RRectDefProcData

                    lda <param          ; find out which part to draw
                    asl a               ; turn into an index into a jump table
                    tax
                    jsr (partToDraw,x)

                    clc
                    rts

partToDraw          dc i2'drawFrame'
                    dc i2'drawGoAway'
                    dc i2'drawZoomBox'
                    dc i2'drawInfoBar'

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Draws the entire frame of a window. This includes the go-away box and any
; other parts of the frame that you may implement (like a zoom box, an
; infobar, scrollbars, grow box, etc.
;
drawFrame           entry
                    pha                 ; save the text mode (on the stack!)
                    _GetTextMode

                    pha
                    _GetPenMode

                    pha                 ; and the color (on the stack!)
                    _GetForeColor

                    _PenNormal

                    jsr GetStrucRect

                    jsr SetColorTable   ; put ptr to a color table into 'work'

;
; Now draw the background of the window. Set the color to the backbround color
; in the color table, then do a PaintRect to draw it all.
;
                    jsr SetBGColor

                    ldy #6              ;Make a local rectangle that
aa                  lda strucRect,y     ;encompasses the title bar.
                    sta pRect,y
                    dey
                    dey
                    bpl aa
                    ldy #titleHeight
                    clc
                    adc [<windGlobals],y
                    dec a
                    sta pRect+4
                    inc pRect

                    pha                 ;Make a rectangular region the
                    pha                 ;same size as this rectangle.
                    _NewRgn
                    lda 1,s
                    sta <workRgn
                    lda 3,s
                    sta <workRgn+2
                    pea pRect|-16
                    pea pRect
                    _RectRgn

                    stz offset
                    stz offset+2
                    PushLong #offset
                    _LocalToGlobal
                    pei <workRgn+2
                    pei <workRgn
                    lda offset+2
                    pha
                    lda offset
                    pha
                    _OffsetRgn

                    ldy #owStrucRgn+2   ; get the handle from the window record
                    lda [<theWindow],y
                    pha
                    dey
                    dey
                    lda [<theWindow],y
                    pha
                    pei <workRgn+2
                    pei <workRgn
                    pei <workRgn+2
                    pei <workRgn
                    _SectRgn

                    stz offset
                    stz offset+2
                    PushLong #offset
                    _GlobalToLocal
                    pei <workRgn+2
                    pei <workRgn
                    lda offset+2
                    pha
                    lda offset
                    pha
                    _OffsetRgn

                    pei <workRgn+2
                    pei <workRgn
                    pea 2
                    pea 0
                    _InsetRgn

                    pei <workRgn+2
                    pei <workRgn
                    _PaintRgn

;
; Draw the frame. Set the outline color and the Pen Width, and use
; 'strucRect' to call FrameRRect.
;

                    ldy #oframeColor    ; set the outline color
                    lda [<work],y       ; in bits 7-4
                    lsr a
                    lsr a
                    lsr a
                    lsr a
                    and #%00001111
                    pha
                    _SetSolidPenPat

                    ldy #lineW          ; now set up the pen size by using the
                    lda [<windGlobals],y ; pen width value the Window Manager
                    pha                 ; passes to us in the Globals section.
                    PushWord #1         ; hardcode the height to 1
                    _SetPenSize

                    PushLong #strucRect ; now draw the entire frame
                    ldy #xowRH          ; these are the radii of the corners
                    lda [<theWindow],y
                    pha
                    ldy #xowRV
                    lda [<theWindow],y
                    pha
                    _FrameRRect

                    lda strucRect       ; calculate the VPos of the dividing
                    ldy #titleHeight    ; line.
                    clc
                    adc [<windGlobals],y
                    dec a

                    ldx strucRect+6     ; push on first X/Y coordinate of a
                    dex                 ; moveTo/lineTo sequence
                    dex
                    phx
                    pha

                    ldx strucRect+2     ; the other X/Y coordinate
                    phx
                    pha

                    _MoveTo             ; draw the dividing line
                    _LineTo

; Position and draw the title. Use 'oTitleColor' in the color table.

                    jsr GetStringXPos

                    PushWord XPos       ; Next position to draw the title
                    ldy #titleYPos      ; let the window manager tell us its
                    PushWord [<windGlobals],y ; vertical position.
                    _Moveto

                    PushWord #modeForeCopy ; set mode to our liking
                    _SetTextMode

                    jsr SetTitleColor   ; set up colors accordingly

                    PushLong TitlePtr   ; draw the title
                    _DrawString

                    jsr WindowActive    ; Is the window active? If so
                    beq noGoAway        ; don't grow goAway box

                    ldy #owFrame        ; does this window have a close
                    lda [<theWindow],y  ; box?
                    and #fClose
                    beq noGoAway        ; no so don't draw one.

                    jsr drawGoAway

noGoAway            ANOP
                    _SetForeColor       ; restore the color and the mode
                    _SetPenMode
                    _SetTextMode

                    rts

offset              ds 4

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Draw JUST the go-away box in the frame. This will ususally be called when
; TrakGoAway needs to (un)hilite it, but it could really be called at any
; time.

drawGoAway          ANOP
                    jsr SetColorTable   ; get a pointer to color table

                    pha                 ; save the text mode (on the stack!)
                    _GetTextMode

                    pha                 ; and the color (on the stack!)
                    _GetForeColor

                    pha                 ; and the color (on the stack!)
                    _GetBackColor

                    PushWord #modeCopy  ; set mode to our liking
                    _SetTextMode

                    ldy #otitleColor    ; set the text color
                    lda [<work],y
                    and #%00001111
                    pha
                    _SetForeColor

                    ldy #otBarColor     ; set the background
                    lda [<work],y
                    and #%00001111
                    pha
                    _SetBackColor

                    pha                 ; save the current font so that we
                    pha                 ; can switch to the Window Manager
                    _GetFont            ; icon font.
                    PullLong OldFont

                    ldy #windIconFont+2 ; Get the Window icons from the
                    PushWord [<windGlobals],y ; window globals area
                    dey
                    dey
                    PushWord [<windGlobals],y
                    _SetFont

                    PushWord #GAX       ; X position for goaway
                    PushWord #GAY       ; Y ditto
                    _MoveTo

                    lda <param+2        ; how are we to draw this?
                    bmi DrawHilited

                    PushWord #0         ; draw a normal go-away box
                    bra DrawIt
DrawHilited         PushWord #1         ; draw a hilited go-away box
DrawIt              _DrawChar

                    PushLong OldFont    ; put the old font back
                    _SetFont

                    _SetBackColor       ; restore the mode and color
                    _SetForeColor       ; restore the mode and color
                    _SetTextMode

                    rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; These aren't implemented.

drawZoomBox         ANOP
drawInfoBar         ANOP
                    rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Utility routines for DrawFrame
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Check the window record to see if there is a pointer to a
; color table there. If there is one, put it into 'work' for
; later use. If there isn't one, use the default provided us
; by the Window Manager in WindGlobals.
;

SetColorTable       ANOP
                    ldy #xowColorPtr    ; set what is pointed to in the
                    lda [<theWindow],y  ; window record. Store it into
                    sta <work           ; 'work' assuming that it is not
                    iny                 ; zero.
                    iny
                    lda [<theWindow],y
                    sta <work+2
                    ora <work           ; is it really zero?
                    bne done            ; no, so use it.

                    ldy #defWindClr     ; yes, it is zero. Use the defaults.
                    lda [<windGlobals],y
                    sta <work
                    iny
                    iny
                    lda [<windGlobals],y
                    sta <work+2
done                ANOP
                    rts


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Do some math to determine where the title string will go. We use
; the formula: (midpoint of the window) - (half the length of the string)
;
;     (left + (right - left) / 2)) - (StringWidth) / 2
;
; which reduces to:
;
;     (left + right - StringWidth) / 2
;

GetStringXPos       ANOP
                    ldy #xowTitle+2     ; get the offset in the record to the
                    lda [<theWindow],y  ; title
                    sta TitlePtr+2
                    dey
                    dey
                    lda [<theWindow],y
                    sta TitlePtr

                    pha                 ; find out how long it is to center it
                    PushLong TitlePtr
                    _StringWidth
                    PullWord XPos       ; save it here for a little bit
;
; now find the left edge of the string by using the equation:
;  (windLeft+windRight-strLen)/2
;
                    ldy #oport+oportRect+6 ; get the right edge of the window
                    lda [<theWindow],y
                    dey
                    dey
                    dey
                    dey
                    clc
                    adc [<theWindow],y  ; add the right edge
                    sec
                    sbc XPos            ; subtract the string's width
                    lsr a               ; divide it all by two
                    sta XPos            ; save the left edge starting position
                    rts



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Get the boundsRect of the StrucRgn in the window record. This allows us
; to do a simple FrameRRect(portRect), which is a lot faster for drawing
; the frame than FrameRgn(strucRgn).

GetStrucRect        Entry               ; also called from myDragRoutine
                    ldy #owStrucRgn     ; get the handle from the window record
                    lda [<theWindow],y
                    sta <work
                    iny
                    iny
                    lda [<theWindow],y
                    sta <work+2

                    ldy #2              ; now dereference into a pointer
                    lda [<work],y
                    tax
                    lda [<work]
                    sta <work
                    stx <work+2

                    ldy #2+6            ; copy the rgnBBox into pRect
                    ldx #6
loop                ANOP
                    lda [<work],y
                    sta strucRect,x
                    dey
                    dey
                    dex
                    dex
                    bpl loop

                    PushLong #strucRect
                    _GlobalToLocal

                    PushLong #strucRect+4
                    _GlobalToLocal
                    rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Find the state of the window (whether it's active or not), and set
; the BackGround color of the Title bar accordingly. These colors are
; obtained from the color table pointed to by 'work'.

SetBGColor          ANOP
                    jsr WindowActive    ; drawing an inactive window?
                    beq Inact1          ; yes, set the right color

                    ldy #otBarColor     ; set the background color
                    lda [<work],y
                    and #%00001111      ; in bits 3-0
                    pha
                    bra SetIt1

Inact1              ANOP
                    ldy #otitleColor    ; set the background color
                    lda [<work],y
                    xba                 ; in bits 11-8
                    and #%00001111
                    pha

SetIt1              ANOP
                    _SetSolidPenPat
                    rts


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; We are about to draw the title in the title bar. This routine gets
; and sets the color for that based on the entry in the color table
; pointed to by 'work'.

SetTitleColor       ANOP
                    jsr WindowActive    ; is this an inactive window?
                    beq Inact2          ; yes

                    ldy #otitleColor    ; set the text color
                    lda [<work],y
                    and #%00001111      ; in bits 3-0
                    pha
                    bra SetIt2

Inact2              ANOP
                    ldy #otitleColor    ; set the text color
                    lda [<work],y
                    lsr a               ; in bits 7-4
                    lsr a
                    lsr a
                    lsr a
                    and #%00001111
                    pha

SetIt2              ANOP
                    _SetForeColor
                    rts


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Short utility routine that returns z=1 if the window is active
; and z=0 if not.
;

WindowActive        ANOP
                    ldy #owFrame
                    lda [<theWindow],y
                    and #fHilited       ; return z=1 if active window
                    rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Local Data Storage
;

TitlePtr            ds 4
XPos                ds 2
OldFont             ds 4                ; holds old font when we switch to
*                                       ; the Window Manager font
                    end
