mirror of
https://github.com/antoinevignau/source.git
synced 2025-01-20 02:30:40 +00:00
1 line
53 KiB
Plaintext
1 line
53 KiB
Plaintext
case obj
|
|
case on
|
|
PRINT PUSH,OFF
|
|
INCLUDE 'BoxCtrl.DefProc.mac'
|
|
PRINT POP
|
|
|
|
*******************************************************************************
|
|
* BoxCtl CDEFProc
|
|
*
|
|
* (C) Copyright Apple Computer, Inc. 1988
|
|
* All rights reserved.
|
|
*
|
|
* by Keith Rollin
|
|
* September 1, 1988
|
|
*
|
|
* This is a Custom Control for the Apple IIGS. It is similar in appearance
|
|
* and action to the 'resize' box you get when clicking on an object in GS Draw
|
|
* or MacDraw.
|
|
*
|
|
* The Control is essentially a frame with 4 or 8 grow knobs on the corners
|
|
* and/or edges. Dragging on any of these knobs will grow the control. Dragging
|
|
* on the frame will move the entire control (like moving a window). A flag can
|
|
* be set so that the control will be dragged if the user clicks in the interior
|
|
* of the control as well. Part codes for the knobs and frame are listed below.
|
|
*
|
|
* Snapping the rectangle's coordinates to a grid is also supported. The
|
|
* rectangle is snapped to the nearest point on the grid. This effectively means
|
|
* that I perform rounding, and not truncating.
|
|
*
|
|
* The frame of the control is the rectangle passed to NewControl. The size of
|
|
* the knobs and the size of the grid are passed in ctlValue. The 'interior drag
|
|
* flag' is passed in ctlFlags. See below for details.
|
|
*
|
|
* Color is supported. Currently, only two colors are used: one for the frame,
|
|
* and one for the knobs. The default colors are black.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
* Modification History:
|
|
*
|
|
* v1.0a1 02-Apr-88 kaar New Today
|
|
* v1.0a2 04-Apr-88 kaar Changed part codes. Defined CtlData to point
|
|
* to a data block. Added edge knobs. Grid can
|
|
* now be rectangular. Knob rectangles no longer
|
|
* part of control (created on the fly). Added
|
|
* new flags to ctlFlag. CtlValue now contains
|
|
* only the size of the knobs.
|
|
* v1.0a3 07-Apr-88 kaar Removed dependance on Direct Page from the
|
|
* application (now uses the stack). Responds to
|
|
* Hilite(255).
|
|
* V1.0a4 08-Apr-88 kaar Added support for when Param1/2 are null.
|
|
* V1.0B1 23-Apr-88 kaar Fixed some bugs. Checked for gridsizes of 0
|
|
* and 1. Called InvalRect in DragCtl.
|
|
* V2.0B2 08-Jun-88 kaar Cleaned up the code some in response to a
|
|
* code review. Version number bumped to 2.0 to
|
|
* reflect existance of simpler 1.0 version for
|
|
* a technote. Added support for fCtlTie in the
|
|
* owner window's frame flags. Improved perfor-
|
|
* mance and legibility of Snap2Grid routine.
|
|
* V2.0B3 08-Jul-88 kaar Part codes changed again. It seems that only
|
|
* one indicator per control is allowed. Turned
|
|
* the source code upside down and put it into
|
|
* Steve Glass format. Implemented some of Dan's
|
|
* programming style suggestions.
|
|
* V2.0 01-Sep-88 kaar First Release
|
|
*
|
|
* V2.01 23-May-90 Greg Branche
|
|
*
|
|
* Added minHeight and minWidth parameters to allow the
|
|
* application to define the minimum width and height of
|
|
* the control. This was formerly handled by the minX
|
|
* and minY parameters. These have been redefined so
|
|
* that they specify the leftmost and uppermost limits
|
|
* of the control. The maxX and maxY parameters specify
|
|
* the right- and bottom-most limits.
|
|
*
|
|
* Bug fixes:
|
|
*
|
|
* 1) In myDrawCtl, the code was never working
|
|
* right that checked the current state of the
|
|
* control to determine whether to draw the control
|
|
* as active or inactive. This has been modified
|
|
* to use a flag passed in the high word of ctlParam
|
|
* as the state indicator. $0000 = control is active,
|
|
* $FFFF = control is inactive.
|
|
*
|
|
* Version 1.0 kaar
|
|
*
|
|
* Used in Custom Control technote
|
|
*
|
|
*
|
|
* Version 2.0 kaar
|
|
*
|
|
* Release for Source Code Demo Disk #1
|
|
*
|
|
*
|
|
* Version 2.01 Greg Branche
|
|
*
|
|
* Used for AppleScan.GS
|
|
*
|
|
*******************************************************************************
|
|
*
|
|
* Part Code returned:
|
|
*
|
|
* $A0 for all parts of the control (all parts are 'indicators')
|
|
*
|
|
*
|
|
* CtlValue: Bits 8-15: width of grow knobs
|
|
* Bits 0- 7: height of grow knobs
|
|
*
|
|
* CtlFlag bits:
|
|
* 7 = 1 - Control is invisible
|
|
* = 0 - Control is visible
|
|
* 2 = 1 - Has edge knobs
|
|
* = 0 - Doesn't
|
|
* 1 = 1 - Has corner knobs
|
|
* = 0 - Doesn't
|
|
* 0 = 1 - Clicking in interior will drag control
|
|
* = 0 - Clicking in interior does nothing
|
|
*
|
|
* Data: Contains a pointer to the following data block. This data
|
|
* block holds the following information, which is copied to
|
|
* the end of the control record:
|
|
*
|
|
* WORD: Min Y when growing (top limit)
|
|
* WORD: Min X when growing (left limit)
|
|
* WORD: Max Y when growing (bottom limit)
|
|
* WORD: Max X when growing (right limit)
|
|
* WORD: Min Height
|
|
* WORD: Min Width
|
|
* WORD: Spacing for Y segment of grid
|
|
* WORD: Spacing for X segment of grid
|
|
*
|
|
* Color Table:
|
|
* WORD: Bits 12-15: <reserved>
|
|
* 8-11: Knob Color
|
|
* 4- 7: Inactive Frame/Knob Color
|
|
* 0- 3: Frame Color
|
|
*
|
|
*******************************************************************************
|
|
*
|
|
* How to use the Control:
|
|
*
|
|
* Initialization and tracking of the control work just like any other;
|
|
* set it up with NewControl. When GetNextEvent returns inContent, call
|
|
* FindControl to see if you hit the control. If you did, call
|
|
* TrackControl.
|
|
*
|
|
* Initialization:
|
|
*
|
|
* pha ; space for result
|
|
* pha
|
|
* PushLong theWindow
|
|
* PushLong #theRect ; pointer to bounding rectangle
|
|
* PushLong #0 ; no title
|
|
* PushWord #%00000111 ; vis, int will drag, corners & edges
|
|
* PushWord #$0503 ; Width = 5/Height = 3
|
|
* PushLong #CtrlData ; Pointer to additional data
|
|
* PushLong #BoxProc ; pointer to DefProc
|
|
* PushLong #0 ; refcon
|
|
* PushLong #0 ; use std color table
|
|
* _NewControl
|
|
* PullLong theControl
|
|
*
|
|
* theRect dc.w 50,140,110,300
|
|
* CtrlData dc.w 10 ; min Y
|
|
* dc.w 10 ; min X
|
|
* dc.w 100 ; max Y
|
|
* dc.w 200 ; max X
|
|
* dc.w 10 ; min height
|
|
* dc.w 16 ; min width
|
|
* dc.w 16 ; grid Y
|
|
* dc.w 32 ; grid X
|
|
*
|
|
*******************************************************************************
|
|
**********************************************************************
|
|
* *
|
|
* Apple IIGS Source Code Sampler, Volume I *
|
|
* *
|
|
* Copyright (c) Apple Computer, Inc. 1988 *
|
|
* All Rights Reserved *
|
|
* *
|
|
* Written by Apple II Developer Tech Support *
|
|
* *
|
|
* *
|
|
* *
|
|
* ---------------------------------------------------------------- *
|
|
* *
|
|
* This program and its derivatives are licensed only for *
|
|
* use on Apple computers. *
|
|
* *
|
|
* Works based on this program must contain and *
|
|
* conspicuously display this notice. *
|
|
* *
|
|
* This software is provided for your evaluation and to *
|
|
* assist you in developing software for the Apple IIGS *
|
|
* computer. *
|
|
* *
|
|
* DISCLAIMER OF WARRANTY *
|
|
* *
|
|
* THE SOFTWARE IS PROVIDED "AS IS" WITHOUT *
|
|
* WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, *
|
|
* WITH RESPECT TO ITS MERCHANTABILITY OR ITS FITNESS *
|
|
* FOR ANY PARTICULAR PURPOSE. THE ENTIRE RISK AS TO *
|
|
* THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH *
|
|
* YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU (AND *
|
|
* NOT APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE) *
|
|
* ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING, *
|
|
* REPAIR OR CORRECTION. *
|
|
* *
|
|
* Apple does not warrant that the functions *
|
|
* contained in the Software will meet your requirements *
|
|
* or that the operation of the Software will be *
|
|
* uninterrupted or error free or that defects in the *
|
|
* Software will be corrected. *
|
|
* *
|
|
* SOME STATES DO NOT ALLOW THE EXCLUSION *
|
|
* OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY *
|
|
* NOT APPLY TO YOU. THIS WARRANTY GIVES YOU SPECIFIC *
|
|
* LEGAL RIGHTS AND YOU MAY ALSO HAVE OTHER RIGHTS *
|
|
* WHICH VARY FROM STATE TO STATE. *
|
|
* *
|
|
* *
|
|
**********************************************************************
|
|
eject
|
|
;-------------------------------------------
|
|
;
|
|
; --- Constants
|
|
;
|
|
; --- Stack Frame/Local Direct Page usage
|
|
;
|
|
|
|
OrigD equ 1 ; caller's saved direct page register
|
|
OrigB equ OrigD+2 ; caller's saved data bank register
|
|
work equ OrigB+1 ; general use work space
|
|
CtlPtr equ work+4 ; pointer to control record
|
|
RtnAddr equ CtlPtr+4 ; RTL address back to Control Manager
|
|
theCtlHandle equ RtnAddr+3 ; handle to control record
|
|
CtlParam equ theCtlHandle+4 ; add'l parameter passed to DefProc
|
|
CtlCode equ CtlParam+4 ; operation to perform
|
|
ReturnValue equ CtlCode+2 ; space for return value to Ctl Mgr.
|
|
|
|
;
|
|
; --- Offsets for my control record
|
|
;
|
|
|
|
oCtlMinY equ octlColor+4
|
|
oCtlMinX equ oCtlMinY+2
|
|
oCtlMaxY equ oCtlMinX+2
|
|
oCtlMaxX equ oCtlMaxY+2
|
|
oCtlMinHeight equ oCtlMaxX+2
|
|
oCtlMinWidth equ oCtlMinHeight+2
|
|
oCtlGridY equ oCtlMinWidth+2
|
|
oCtlGridX equ oCtlGridY+2
|
|
oCtlSize equ oCtlGridX+2
|
|
|
|
;
|
|
; --- Part codes for my control
|
|
;
|
|
|
|
BoxCtlPart equ $A0 ; This is returned to the app.
|
|
|
|
FramePart equ $01 ; These are used internally to tell
|
|
InteriorPart equ $02 ; 'myDragCtl' what part of the
|
|
ULPart equ $03 ; control we are dragging.
|
|
TopPart equ $04
|
|
URPart equ $05
|
|
RightPart equ $06
|
|
LLPart equ $07
|
|
BottomPart equ $08
|
|
LRPart equ $09
|
|
LeftPart equ $0A
|
|
|
|
|
|
;
|
|
; --- Masks for ctlFlags
|
|
;
|
|
|
|
dragIntMask equ %00000001 ; if set, let user drag on interior
|
|
knobCornerMask equ %00000010 ; if set, draw knobs on the corners
|
|
knobEdgeMask equ %00000100 ; if set, draw knobs on the edges
|
|
visMask equ ctlInVis
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
CtlData RECORD
|
|
*
|
|
* Description: Storage for CDEF
|
|
*
|
|
*
|
|
* External Refs: NONE
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
|
|
deltaX ds.b 2 ; used when growing the control
|
|
deltaY ds.b 2
|
|
ColorPtr ds.b 4 ; pointer to actual color table to use
|
|
theParam ds.b 4 ; copy of CtlParam passed on stack
|
|
dragPart ds.b 2 ; internal part of control hit
|
|
|
|
myCtlRect ds.b 8 ; copy of CtlRect in control record
|
|
myCtlGridY ds.b 2 ; copy of CtlGridY
|
|
myCtlGridX ds.b 2 ; copy of CtlGridX
|
|
|
|
FrameHeight ds.b 2
|
|
FrameWidth ds.b 2
|
|
|
|
knobUL ds.b 8 ; This space is used to store the
|
|
knobTop ds.b 8 ; rectangles that define the grow
|
|
knobUR ds.b 8 ; knobs on the control. They are
|
|
knobRight ds.b 8 ; created as needed, and are not
|
|
knobLR ds.b 8 ; stored in the control record.
|
|
knobBottom ds.b 8
|
|
knobLL ds.b 8
|
|
knobLeft ds.b 8
|
|
|
|
StdColorTable dc.b $C0 ; grey inact frame, blk normal frame
|
|
dc.b $00 ; black knobs
|
|
StdCtlData dc.w 10,10,200,640,0,0 ; min 10,10; max 200,640; no grid
|
|
oldPenState ds.b $32 ; storage for old pen state.
|
|
|
|
GreyPattern dc.b $CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC
|
|
dc.b $CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC
|
|
dc.b $CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC
|
|
dc.b $CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC
|
|
|
|
ENDR
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
BoxProc PROC Export
|
|
*
|
|
* Description: Main Routine for Custom Control.
|
|
*
|
|
*
|
|
* Inputs: On entry, the parameters are passed to us on the stack.
|
|
*
|
|
* | | Previous Contents
|
|
* |-------------------|
|
|
* | ReturnValue | LONG - Space for return value
|
|
* |-------------------|
|
|
* | CtlCode | WORD - operation to perform
|
|
* |-------------------|
|
|
* | CtlParam | LONG - add'l parameter
|
|
* |-------------------|
|
|
* | theCtlHandle | LONG - Handle to control record
|
|
* |-------------------|
|
|
* | RtnAddr | 3 BYTES - RTL address
|
|
* |-------------------|
|
|
* | | <-- Stack pointer
|
|
*
|
|
* Outputs: Put something into ReturnValue, pull off the parameters,
|
|
* and return to the Control Manager.
|
|
*
|
|
* | | Previous Contents
|
|
* |-------------------|
|
|
* | ReturnValue | LONG - Space for return value
|
|
* |-------------------|
|
|
* | RtnAddr | 3 BYTES - RTL address
|
|
* |-------------------|
|
|
* | | <-- Stack pointer
|
|
*
|
|
* External Refs:
|
|
import InitCtlData
|
|
import myDrawCtl
|
|
import myTestCtl
|
|
import myInitCtl
|
|
import myDragCtl
|
|
import myNewValue
|
|
import mySetParams
|
|
import myRecSize
|
|
import Null
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
with CtlData
|
|
|
|
;
|
|
; We are going to be using the stack as our direct page for the
|
|
; custom control. The equates listed at the beginning of the custom
|
|
; control (right after the pageful of comments that explain it)
|
|
; describe the layout of the stack frame.
|
|
;
|
|
; The way we set up the stack frame as our direct page is by first
|
|
; saving the old contents of the DP register, transfering the stack
|
|
; pointer to the accumulator, and then transferring that to the DP
|
|
; register. We also save the contents of the Data Bank Register and
|
|
; reset it to the Program Bank Register so that we don't have to
|
|
; use 3-byte long addressing anywhere. We will restore both of these
|
|
; registers when we leave the custom control.
|
|
;
|
|
|
|
pha ; push on some room for 'CtlPtr'
|
|
pha
|
|
pha ; push on some room for 'work'
|
|
pha
|
|
|
|
phb ; save the Data Bank register
|
|
phd ; save the Direct Page register
|
|
|
|
phk ; switch data bank to program bank
|
|
plb
|
|
tsc ; switch Direct Page into stack
|
|
tcd
|
|
|
|
jsr InitCtlData ; init some handy data
|
|
|
|
lda <CtlCode ; get routine # to call
|
|
cmp #recSize+1 ; we only know of 12 CtlCodes
|
|
blt ShiftIt
|
|
lda #6 ; force unknown codes to null events
|
|
ShiftIt
|
|
asl a
|
|
tax
|
|
jsr (CtlTable,x)
|
|
|
|
sta <ReturnValue ; save the return value
|
|
stx <ReturnValue+2
|
|
|
|
;
|
|
; The Return Value has been stored on the stack, and it is time for us to
|
|
; return back to the Control Manager. Before we do so, however, we must
|
|
; remove the parameters that were passed to us on the stack. We do this
|
|
; by moving the RTL address up just below the Return Value, getting the
|
|
; stack pointer, and adding an amount to it so that we point to where
|
|
; the RTL address has been moved to. We can then simply RTL back to the
|
|
; Control Manager, and it will pick up the Return Value right off of the
|
|
; stack!
|
|
;
|
|
lda <RtnAddr ; move the return address up
|
|
sta <ReturnValue-3
|
|
lda <RtnAddr+1
|
|
sta <ReturnValue-2
|
|
|
|
tsc ; Get the stack pointer
|
|
|
|
pld ; restore caller's Data Bank and
|
|
plb ; Direct Page registers
|
|
|
|
clc ; Adjust the stack pointer to point to
|
|
adc #ReturnValue-4 ; the new location of the RTL address.
|
|
tcs ; Put the stack pointer back.
|
|
|
|
rtl ; back to the caller
|
|
|
|
|
|
; This is a table of pointers to routines to be called for specific
|
|
; CtlCodes passed to us. The 'null' entries are pointers to a
|
|
; routine that does nothing except return 'no error'.
|
|
|
|
CtlTable
|
|
dc.w myDrawCtl ; 0 drawCtl
|
|
dc.w Null ; 1 calcCRect
|
|
dc.w myTestCtl ; 2 testCtl
|
|
dc.w myInitCtl ; 3 initCtl
|
|
dc.w Null ; 4 dispCtl
|
|
dc.w Null ; 5 posCtl
|
|
dc.w Null ; 6 thumbCtl
|
|
dc.w myDragCtl ; 7 dragCtl
|
|
dc.w Null ; 8 autoTrack
|
|
dc.w myNewValue ; 9 newValue
|
|
dc.w mySetParams ;10 setParams
|
|
dc.w myInitCtl ;11 moveCtl
|
|
dc.w myRecSize ;12 recSize
|
|
|
|
ENDP
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
myDrawCtl PROC
|
|
*
|
|
* Description: Draw control command.
|
|
*
|
|
*
|
|
* Inputs: NONE
|
|
*
|
|
* Outputs: NONE
|
|
*
|
|
* External Refs:
|
|
import CalcCorners
|
|
import SetMyPen
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
with CtlData
|
|
|
|
; figure out the coordinates of the grow knobs.
|
|
|
|
jsr CalcCorners
|
|
|
|
; Save the pen state, as we'll be changing it a lot.
|
|
|
|
PushLong #oldPenState
|
|
_GetPenState
|
|
|
|
; Set the correct width of the pen for the mode we are in.
|
|
|
|
jsr SetMyPen
|
|
|
|
;
|
|
; Set the local variable 'ActivFlag' to indicate how to draw the
|
|
; control. We draw it inactive if a) the Hilite value is 255, or b)
|
|
; the owner window is inactive and fCtrlTie is set.
|
|
;
|
|
ldy #octlHilite ; are we inactive?
|
|
lda [<CtlPtr],y
|
|
and #$00FF
|
|
cmp #$00FF
|
|
beq DrawInactive ; yes, so clear ActivFlag
|
|
|
|
; At this point, the control can potentially be drawn as an active
|
|
; control. But this can only happen if the window is active, or is
|
|
; inactive but with the fCtlTie flag clear.
|
|
|
|
lda CtlParam+2 ; get the flag passed by the Control Manager
|
|
bmi DrawInactive ; $FFFF = inactive
|
|
|
|
DrawActive lda #1
|
|
sta ActivFlag
|
|
bra SetColorTable
|
|
|
|
DrawInactive stz ActivFlag
|
|
|
|
; Put the color table pointer into a Direct page location.
|
|
|
|
SetColorTable
|
|
lda ColorPtr
|
|
sta <work
|
|
lda ColorPtr+2
|
|
sta <work+2
|
|
|
|
;
|
|
; See if the control is active or not, and set the color
|
|
; accordingly.
|
|
;
|
|
|
|
lda ActivFlag
|
|
bne SetFrameColor
|
|
|
|
lda [<work] ; YES - so we are. Use the inactive
|
|
lsr a ; pattern for this.
|
|
lsr a
|
|
lsr a
|
|
lsr a
|
|
and #$000f
|
|
pha
|
|
_SetSolidPenPat
|
|
|
|
bra DrawFrame
|
|
|
|
SetFrameColor
|
|
lda [<work] ; get the color for the frame from
|
|
and #$000f ; the color table and use it.
|
|
pha
|
|
_SetSolidPenPat
|
|
|
|
DrawFrame
|
|
PushLong #myCtlRect ; draw the frame of the control
|
|
_FrameRect
|
|
|
|
;
|
|
; See if the control is active or not, and set the color accordingly. If
|
|
; we so chose we could even decide not to draw knobs on an inactive sizer.
|
|
; This is similar to the scrollbar defproc no drawing the thumb on an
|
|
; inactive scrollbar.
|
|
;
|
|
|
|
lda ActivFlag
|
|
beq DrawKnobs ; it's inactive; keep that pattern
|
|
|
|
lda [<work] ; get the color of the knobs from
|
|
xba ; the color table and set it.
|
|
and #$000f
|
|
pha
|
|
_SetSolidPenPat
|
|
|
|
DrawKnobs
|
|
ldy #octlFlag ; do we need corner knobs?
|
|
lda [<CtlPtr],y
|
|
and #knobCornerMask
|
|
beq ckEdges ; no, so check for edge knobs.
|
|
|
|
PushLong #knobUL ; yes, so draw them
|
|
_PaintRect
|
|
|
|
PushLong #knobUR
|
|
_PaintRect
|
|
|
|
PushLong #knobLL
|
|
_PaintRect
|
|
|
|
PushLong #knobLR
|
|
_PaintRect
|
|
|
|
ckEdges
|
|
ldy #octlFlag ; do we need edge knobs?
|
|
lda [<CtlPtr],y
|
|
and #knobEdgeMask
|
|
beq done ; no, so leave
|
|
|
|
PushLong #knobTop ; yes, so draw them.
|
|
_PaintRect
|
|
|
|
PushLong #knobRight
|
|
_PaintRect
|
|
|
|
PushLong #knobBottom
|
|
_PaintRect
|
|
|
|
PushLong #knobLeft
|
|
_PaintRect
|
|
|
|
done
|
|
PushLong #oldPenState ; clean up after ourselves.
|
|
_SetPenState
|
|
|
|
lda #0
|
|
tax
|
|
|
|
rts
|
|
|
|
ActivFlag ds.b 2
|
|
|
|
ENDP
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
myTestCtl PROC
|
|
*
|
|
* Description: Hit test command. This routine checks to see if we have
|
|
* chosen the ability to drag the control when we click in
|
|
* the interior or not. If so, then we will always return
|
|
* our partcode (BoxCtlPart = $A0). If not, then we only
|
|
* return our partcode if we click on the frame or a knob.
|
|
*
|
|
*
|
|
* Inputs: NONE
|
|
*
|
|
* Outputs: A = Part code hit
|
|
*
|
|
* External Refs:
|
|
import TestFrame
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
with CtlData
|
|
|
|
jsr TestFrame
|
|
cmp #noPart ; hit anything?
|
|
beq exit ; no - return nothing
|
|
lda #BoxCtlPart ; yes - return our partcode
|
|
exit
|
|
ldx #0 ; high byte of return value always $00
|
|
rts
|
|
|
|
ENDP
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
myInitCtl PROC
|
|
*
|
|
* Description: Called to initialize my custom fields of the control
|
|
* record. It calles mySetParams to handle the data that
|
|
* is pointed to by the Data/Params field, and makes sure
|
|
* that the corners of the rectangle lie on the grid.
|
|
*
|
|
*
|
|
* Inputs: NONE
|
|
*
|
|
* Outputs: NONE
|
|
*
|
|
* External Refs:
|
|
import mySetParams
|
|
import Snap2Grid
|
|
import SetCtlRect
|
|
import InitCtlData
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
with CtlData
|
|
|
|
; First, set up some fields based on the value of Param. This is
|
|
; a pointer to some additional data, so what SetParams does is
|
|
; copy that into our control record.
|
|
|
|
jsr mySetParams
|
|
jsr InitCtlData
|
|
|
|
; Next, make sure the edges of the control are aligned to a grid.
|
|
|
|
ldx #^myCtlRect
|
|
lda #myCtlRect
|
|
jsr Snap2Grid
|
|
|
|
jsr SetCtlRect
|
|
|
|
lda #0 ; return nothing
|
|
txa
|
|
|
|
rts
|
|
ENDP
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
myDragCtl PROC
|
|
*
|
|
* Description: Drag command. We hit something. Determine what it was and
|
|
* drag it around the screen. If we hit the frame, then drag
|
|
* the whole control. If we hit a knob, then we grow the
|
|
* control (just like growing a window).
|
|
*
|
|
*
|
|
* Inputs: NONE
|
|
*
|
|
* Outputs: NONE
|
|
*
|
|
* External Refs:
|
|
import SetMyPen
|
|
import Snap2Grid
|
|
import myDrawCtl
|
|
import FindPart
|
|
import SetCtlRect
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
with CtlData
|
|
|
|
PushLong #oldPenState ; save drawing state, as we change it
|
|
_GetPenState
|
|
|
|
ldx #6 ; copy original control rect to drag_rect
|
|
@loop
|
|
lda myCtlRect,x
|
|
sta drag_rect,x
|
|
dex
|
|
dex
|
|
bpl @loop
|
|
|
|
ldy #oCtlMaxX ; get local copies of the maximum
|
|
ldx #6 ; and minimum dimensions.
|
|
loop0010 lda [<CtlPtr],y
|
|
sta limitRect,x
|
|
dey
|
|
dey
|
|
dex
|
|
dex
|
|
bpl loop0010
|
|
|
|
ldy #oCtlMinHeight
|
|
lda [<CtlPtr],y
|
|
sta MinHeight
|
|
iny
|
|
iny
|
|
lda [<CtlPtr],y
|
|
sta MinWidth
|
|
|
|
; Get the portRect of the window that owns this control. This rectangle
|
|
; will be used to control the limits of dragging.
|
|
|
|
ldy #octlOwner ; get the pointer to the control's
|
|
lda [<CtlPtr],y ; owning window into 'work'
|
|
sta <work
|
|
iny
|
|
iny
|
|
lda [<CtlPtr],y
|
|
sta <work+2
|
|
|
|
ldy #oportRect+6 ; copy the PortRect of the window
|
|
ldx #6 ; out of its GrafPort into slopRect.
|
|
loop400 lda [<work],y
|
|
sta slopRect,x
|
|
dey
|
|
dey
|
|
dex
|
|
dex
|
|
bpl loop400
|
|
|
|
; Now we adjust slopRect to account for the width of the knobs
|
|
|
|
ldy #octlValue ; get the height of the knobs
|
|
lda [<CtlPtr],y
|
|
and #$00ff
|
|
pha
|
|
clc
|
|
adc slopRect
|
|
sta slopRect
|
|
lda slopRect+4
|
|
sec
|
|
sbc 1,s
|
|
sta slopRect+4
|
|
pla ; remove from stack
|
|
|
|
lda [<CtlPtr],y ; get the width of the knobs
|
|
xba
|
|
and #$00ff
|
|
pha
|
|
clc
|
|
adc slopRect+2
|
|
sta slopRect+2
|
|
lda slopRect+6
|
|
sec
|
|
sbc 1,s
|
|
sta slopRect+6
|
|
; ; leave on stack as space for result of GetNextEvent
|
|
|
|
; pha ; has the mouse been lifted up?
|
|
PushWord #mUpMask ; ask for any such events
|
|
PushLong #TrackEvent
|
|
_GetNextEvent
|
|
pla
|
|
|
|
lda TrackEvent+owhat
|
|
cmp #mouseUpEvt ; was there a mouse up event?
|
|
bne mDown ; no - so start tracking
|
|
brl done ; yes - so leave
|
|
|
|
mDown
|
|
PushLong #TrackEvent+owhere
|
|
_GlobalToLocal
|
|
|
|
lda TrackEvent+owhere
|
|
sta OldMouse ; FindPart likes the mouse Position
|
|
sta theParam ; in 'theParam'
|
|
lda TrackEvent+owhere+2
|
|
sta OldMouse+2
|
|
sta theParam+2
|
|
|
|
jsr FindPart ; what did we hit? (returns internal
|
|
sta dragPart ; partcode number).
|
|
|
|
cmp #InteriorPart+1 ; what part did we hit?
|
|
bge GrowFrame ; some knob - grow the control
|
|
brl DragFrame ; interior or frame - move the control
|
|
|
|
;
|
|
; This part of the program is called when we detect that we have clicked on
|
|
; a grow knob. It tracks the motions of the mouse, and grows/draws the
|
|
; control appropriately.
|
|
;
|
|
GrowFrame
|
|
PushWord #2 ; set us to XOR mode. This is for the
|
|
_SetPenMode ; rubber-banding effect of growing.
|
|
|
|
jsr SetMyPen ; set my pen's width
|
|
|
|
PushLong #GreyPattern ; grow with a grey pattern
|
|
_SetPenPat
|
|
|
|
; validate the min and max values. the min values must be at least $4.
|
|
; if not, they are set there. the max values must be at least as large
|
|
; as the min values. if not, they are set to $FFFF
|
|
|
|
lda #4
|
|
cmp MinWidth
|
|
blt ckMinY
|
|
sta MinWidth
|
|
|
|
ckMinY cmp MinHeight
|
|
blt ckMaxX
|
|
sta MinHeight
|
|
|
|
ckMaxX lda limitRect+6
|
|
sec
|
|
sbc MinWidth
|
|
cmp limitRect+2
|
|
bge ckMaxY
|
|
ChgX lda #$FFFF
|
|
sta limitRect+6
|
|
|
|
ckMaxY lda limitRect+4
|
|
sec
|
|
sbc MinHeight
|
|
cmp limitRect
|
|
bge doneCk
|
|
ChgY lda #$FFFF
|
|
sta limitRect+4
|
|
doneCk
|
|
lda myCtlRect+4 ; get lower boundary
|
|
sec
|
|
sbc MinHeight ; calculate theoretical upper boundary
|
|
sta minRect ; store it as upper limit
|
|
lda myCtlRect ; get upper boundary
|
|
clc
|
|
adc MinHeight ; calculate
|
|
sta minRect+4 ; store as lower limit
|
|
lda myCtlRect+6 ; get right boundary
|
|
sec
|
|
sbc MinWidth ; calculate
|
|
sta minRect+2 ; store as left limit
|
|
lda myCtlRect+2 ; get left boundary
|
|
clc
|
|
adc MinWidth ; calculate
|
|
sta minRect+6 ; store as right limit
|
|
|
|
;
|
|
; We grow the control with the following algorithm. First, setup by:
|
|
;
|
|
; 1. saving the current mouse postion in 'NewMouse',
|
|
; 2. aligning 'NewMouse' to the grid, and
|
|
; 3. making a working copy of the control's rectangle in 'drag_rect'.
|
|
;
|
|
; We then enter the main loop:
|
|
;
|
|
; 4. Draw a copy of the rubber-banding rectangle.
|
|
; 5. Check the mouse button. If it is up, goto #12
|
|
; 6. Put the position of the mouse into 'NewerMouse'. Align it to grid.
|
|
; 7. Check it against 'NewMouse'. If it hasn't changed, goto #5.
|
|
; 8. Erase the old rubber-Band.
|
|
; 9. Calculate the new rectangle and put it into 'drag_rect'
|
|
; 10. Move 'NewerMouse' into 'NewMouse'
|
|
; 11. Goto #4
|
|
;
|
|
; The growing is all done. Clean up and leave.
|
|
;
|
|
; 12. Erase the rubber band.
|
|
; 13. Erase the control.
|
|
; 14. Invalidate the area under the control
|
|
; 15. Make drag_rect the new boundary of the control
|
|
; 16. Say goodnite, Gracie.
|
|
;
|
|
|
|
lda OldMouse
|
|
sta NewMouse
|
|
lda OldMouse+2
|
|
sta NewMouse+2
|
|
|
|
ldx #^NewMouse ; make sure we are on the grid!!!
|
|
lda #NewMouse
|
|
jsr Snap2Grid
|
|
|
|
DrawLoop
|
|
PushLong #drag_rect ; draw the rubber-band
|
|
_FrameRect
|
|
|
|
WaitLoop
|
|
pha ; has the mouse been lifted up?
|
|
PushWord #mUpMask ; ask for any such events
|
|
PushLong #TrackEvent
|
|
_GetNextEvent
|
|
pla
|
|
|
|
lda TrackEvent+owhat
|
|
cmp #mouseUpEvt
|
|
beq done ; mouse up occured - so leave.
|
|
|
|
lda TrackEvent+owhere ; mouse still down. copy it to
|
|
sta NewerMouse ; NewerMouse
|
|
lda TrackEvent+owhere+2
|
|
sta NewerMouse+2
|
|
|
|
PushLong #NewerMouse ; convert it to window coordinates.
|
|
_GlobalToLocal
|
|
|
|
ldx #^NewerMouse ; make sure the new position is on
|
|
lda #NewerMouse ; the grid.
|
|
jsr Snap2Grid
|
|
|
|
lda NewerMouse ; See if the mouse position moved. We
|
|
cmp NewMouse ; only redraw the rubber-band if it did.
|
|
bne ReDraw ; It did - redraw the rubber-band
|
|
lda NewerMouse+2
|
|
cmp NewMouse+2
|
|
beq WaitLoop ; No movement - check button state
|
|
|
|
ReDraw
|
|
PushLong #drag_rect ; erase the old rubber band
|
|
_FrameRect
|
|
|
|
lda NewerMouse ; copy NewerMouse for next loop
|
|
sta NewMouse
|
|
sec ; and update deltaXY for AdjFrameRect
|
|
sbc OldMouse
|
|
sta deltaY
|
|
|
|
lda NewerMouse+2
|
|
sta NewMouse+2
|
|
sec
|
|
sbc OldMouse+2
|
|
sta deltaX
|
|
|
|
jsr AdjFrameRect ; adjust for drawing the new rect
|
|
|
|
brl DrawLoop ; redraw the rubber-band
|
|
|
|
done
|
|
PushLong #drag_rect ; erase the rubber band
|
|
_FrameRect
|
|
|
|
PushLong #myCtlRect ; erase the control
|
|
_EraseRect
|
|
|
|
PushLong #myCtlRect ; invalidate the stuff under it
|
|
_InvalRect
|
|
|
|
brl Exit
|
|
;
|
|
; This part of the program is called when we have clicked on either the
|
|
; frame or the interior. It calls dragrect to move an outline of the
|
|
; control around.
|
|
;
|
|
|
|
DragFrame
|
|
|
|
;
|
|
; Use dragRect to drag an outline of the control around the
|
|
; screen for me.
|
|
;
|
|
pha ; space for result
|
|
pha
|
|
PushLong #DragDraw ; no action proc
|
|
PushLong #GreyPattern ; drag pattern
|
|
PushLong OldMouse ; starting location of mouse
|
|
PushLong #drag_rect ; outline to drag
|
|
PushLong #limitRect ; rect defining limits
|
|
PushLong #slopRect ; slopRect
|
|
PushWord #%00101000 ; custom drag flag, ReturnRect flag
|
|
_DragRect
|
|
|
|
pla ; pull off and discard the deltas
|
|
pla
|
|
|
|
PushLong #myCtlRect ; erase the control in its old pos'n
|
|
_EraseRect
|
|
|
|
PushLong #myCtlRect ; invalidate the stuff under it
|
|
_InvalRect
|
|
|
|
ldx #^drag_rect ; align the new rectangle to the grid.
|
|
lda #drag_rect
|
|
jsr Snap2Grid
|
|
|
|
Exit
|
|
ldy #6 ; copy over the new control frame
|
|
loop200 lda drag_rect,y
|
|
sta myCtlRect,y
|
|
dey
|
|
dey
|
|
bpl loop200
|
|
|
|
PushLong #myCtlRect ; Invalidate the new area under the
|
|
_InvalRect ; control so it will be redrawn.
|
|
|
|
PushLong #oldPenState
|
|
_SetPenState ; clean up QuickDraw after ourselves.
|
|
|
|
jsr SetCtlRect ; copy new rect into control record
|
|
|
|
lda #-1 ; Say that we handled it
|
|
tax
|
|
|
|
rts
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;
|
|
; Called by DragRect to draw the rectangle of the control. I draw the outline
|
|
; myself so that I can align it to my own grid. The normal aligning of the
|
|
; rectangle to the grid only aligns to powers of 2. I align to anything.
|
|
;
|
|
; When this routine is called, the stack looks like this:
|
|
;
|
|
; PUSH:WORD - delta X
|
|
; PUSH:WORD - delta Y
|
|
; PUSH:BYTE[3] - return address
|
|
;
|
|
; However, since I set the ReturnRect flag, I can ignore the deltas passed to
|
|
; me, and use drag_rect directly. I make a copy of it, make sure that it is
|
|
; aligned to the grid, draw it, remove the parameters, and return to the
|
|
; control manager.
|
|
;
|
|
|
|
DragDraw
|
|
|
|
RTLAddr equ 1
|
|
DY equ RTLAddr+3
|
|
DX equ DY+2
|
|
|
|
ldx #6 ; make a copy of the rectangle that
|
|
loop500 lda drag_rect,x ; _DragRect is passing to us. We are
|
|
sta draw_rect,x ; going to modify it so that it is
|
|
dex ; aligned to the grid.
|
|
dex
|
|
bpl loop500
|
|
|
|
ldx #^draw_rect ; align the new rectangle to the grid.
|
|
lda #draw_rect
|
|
jsr Snap2Grid
|
|
|
|
DrawOutline
|
|
PushLong #draw_rect
|
|
_FrameRect
|
|
|
|
ExitDragDraw
|
|
lda 1,s ; move the RTL address back up
|
|
sta 5,s
|
|
lda 2,s
|
|
sta 6,s
|
|
|
|
pla ; remove the parameters (DX, DY)
|
|
pla
|
|
|
|
rtl ; back to dragRect!!
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;
|
|
; Called by the routine that grows the control with a rubber-band
|
|
; sort of thing. It uses the part code we hit as an index into
|
|
; a table. This table contains a list of offsets into the
|
|
; 4 words of drag_rect. It reads in a pair of these offsets and
|
|
; uses them to modify the appropriate X/Y coordinates with
|
|
; deltaY and deltaX. DeltaY and deltaX are set up by the
|
|
; rubber-banding routine.
|
|
|
|
AdjFrameRect
|
|
ldx #6
|
|
loop380 lda drag_rect,x
|
|
sta new_rect,x
|
|
dex
|
|
dex
|
|
bpl loop380
|
|
|
|
lda dragPart ; get the part code we are dragging
|
|
sec
|
|
sbc #ULPart
|
|
asl a ; turn it into an index.
|
|
asl a
|
|
tax
|
|
lda PtToAdj,x ; get Y coordinate to adjust
|
|
tay
|
|
lda PtToAdj+2,x ; get X coordinate to adjust
|
|
tax
|
|
|
|
; if the entry that was fetched from the table was -1, then that means
|
|
; that we are making no adjustments in that direction. For instance, it
|
|
; we are dragging on the top edge knob, we want to adjust just the top
|
|
; side of the rectangle, but want to leave either of the sides alone.
|
|
|
|
cpy #-1 ; modify the vertical coordinate
|
|
beq NoChg1 ; of choice if necessary.
|
|
clc
|
|
lda deltaY
|
|
adc myCtlRect,y
|
|
sta new_rect,y
|
|
|
|
NoChg1 cpx #-1 ; modify the horizontal coordinate
|
|
beq NoChg2 ; of choice if necessary.
|
|
clc
|
|
lda deltaX
|
|
adc myCtlRect,x
|
|
sta new_rect,x
|
|
|
|
NoChg2
|
|
ldx #^new_rect ; align the rectangle to the grid.
|
|
lda #new_rect
|
|
jsr Snap2Grid
|
|
|
|
; now that we have a new rectangle, we have to make sure that it is within
|
|
; the maximum and minimum sizes allowed.
|
|
|
|
; First, we check to make sure the new rect is within the slopRect. If not
|
|
; we revert back to the original rect position. This mimics the action of
|
|
; DragRect.
|
|
|
|
pha ; space for result
|
|
pushlong #NewMouse ; put point on stack
|
|
pushlong #slopRect ; put slopRect on stack
|
|
_PtInRect
|
|
pla ; retrieve result
|
|
bne inRect ; yes, the new point is within slopRect
|
|
|
|
copyOriginal
|
|
ldx #6 ; copy original control rect to drag_rect
|
|
@loop
|
|
lda myCtlRect,x
|
|
sta drag_rect,x
|
|
dex
|
|
dex
|
|
bpl @loop
|
|
rts
|
|
inRect
|
|
|
|
; Now we can check to make sure the new rect is within the bounds of the
|
|
; limit rect. If it isn't, we peg it at the limit, again mimicking
|
|
; DragRect.
|
|
|
|
lda limitRect ; outside the top limit?
|
|
cmp new_rect
|
|
bcc @1 ; no...
|
|
sta new_rect ; else peg it there
|
|
@1
|
|
lda limitRect+2 ; how 'bout the left limit?
|
|
cmp new_rect+2
|
|
bcc @2
|
|
sta new_rect+2
|
|
@2
|
|
lda limitRect+4
|
|
cmp new_rect+4
|
|
bcs @3
|
|
sta new_rect+4
|
|
@3
|
|
lda limitRect+6
|
|
cmp new_rect+6
|
|
bcs @4
|
|
sta new_rect+6
|
|
@4
|
|
lda minRect ; now check the width and height for minimums
|
|
cmp new_rect
|
|
bcs @5
|
|
sta new_rect
|
|
@5
|
|
lda minRect+2
|
|
cmp new_rect+2
|
|
bcs @6
|
|
sta new_rect+2
|
|
@6
|
|
lda minRect+4
|
|
cmp new_rect+4
|
|
bcc @7
|
|
sta new_rect+4
|
|
@7
|
|
lda minRect+6
|
|
cmp new_rect+6
|
|
bcc @8
|
|
sta new_rect+6
|
|
@8
|
|
ldx #6 ; now we can copy the new rect to drag_rect
|
|
@loop2
|
|
lda new_rect,x
|
|
sta drag_rect,x
|
|
dex
|
|
dex
|
|
bpl @loop2
|
|
|
|
rts
|
|
|
|
|
|
PtToAdj dc.w 0,2,0,-1,0,6,-1,6,4,6,4,-1,4,2,-1,2
|
|
|
|
TrackEvent ds.b $10
|
|
|
|
OldMouse ds.b 4
|
|
NewMouse ds.b 8
|
|
NewerMouse ds.b 8
|
|
drag_rect ds.b 8
|
|
draw_rect ds.b 8
|
|
old_drag ds.b 8
|
|
new_rect ds.b 8
|
|
limitRect ds.b 8
|
|
slopRect ds.b 8
|
|
minRect ds.b 8
|
|
MinHeight ds.b 2
|
|
MinWidth ds.b 2
|
|
|
|
ENDP
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
myNewValue PROC
|
|
*
|
|
* Description: Called when the value of the control is to be changed.
|
|
* The area under the control is invalidated so that it will
|
|
* be redrawn.
|
|
*
|
|
*
|
|
* Inputs: NONE
|
|
*
|
|
* Outputs: NONE
|
|
*
|
|
* External Refs:
|
|
import Snap2Grid
|
|
import myDrawCtl
|
|
import SetCtlRect
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
with CtlData
|
|
|
|
PushLong #myCtlRect ; erase old control
|
|
_EraseRect
|
|
|
|
PushLong #myCtlRect ; invalidate area erased
|
|
_InvalRect
|
|
|
|
ldx #^myCtlRect ; make sure control is on the grid
|
|
lda #myCtlRect
|
|
jsr Snap2Grid
|
|
|
|
jsr SetCtlRect
|
|
|
|
lda #0 ; return no value
|
|
tax
|
|
|
|
rts
|
|
ENDP
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
mySetParams PROC
|
|
*
|
|
* Description: Set new parameters command. Don't set if either of them
|
|
* are negative.
|
|
*
|
|
*
|
|
* Inputs: NONE
|
|
*
|
|
* Outputs: NONE
|
|
*
|
|
* External Refs: NONE
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
with CtlData
|
|
|
|
lda theParam ; these have gotta go on in reverse
|
|
sta <work+2
|
|
lda theParam+2
|
|
sta <work
|
|
|
|
ora <work+2 ; is this a NULL pointer?
|
|
bne CopyIt ; no - so use it
|
|
|
|
lda #^StdCtlData ; yes - so set pointer to default data
|
|
sta <work+2
|
|
lda #StdCtlData
|
|
sta <work
|
|
|
|
CopyIt
|
|
ldy #oCtlSize-2 ; copy the data into control record.
|
|
ldx #oCtlSize-oCtlMinY-2
|
|
loop phy
|
|
txy
|
|
lda [<work],y
|
|
ply
|
|
sta [<CtlPtr],y
|
|
dey
|
|
dey
|
|
dex
|
|
dex
|
|
bpl loop
|
|
|
|
lda #0 ; return no value
|
|
tax
|
|
|
|
rts
|
|
ENDP
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
myRecSize PROC
|
|
*
|
|
* Description: Return record size command.
|
|
*
|
|
*
|
|
* Inputs: NONE
|
|
*
|
|
* Outputs: A = Size of the control record to allocate.
|
|
*
|
|
* External Refs: NONE
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
with CtlData
|
|
|
|
lda #oCtlSize ; low word of record size
|
|
ldx #0 ; high word
|
|
|
|
rts
|
|
ENDP
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
Null PROC
|
|
*
|
|
* Description: Null routine. Does nothing. Returns no error.
|
|
*
|
|
*
|
|
* Inputs: NONE
|
|
*
|
|
* Outputs: NONE
|
|
*
|
|
* External Refs: NONE
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
|
|
lda #0
|
|
tax
|
|
|
|
rts
|
|
ENDP
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
InitCtlData PROC
|
|
*
|
|
* Description: Initialize some data that will needs to be handy: Get a
|
|
* pointer to the control record (we are supplied only with
|
|
* a handle), make a local copy of the control rectangle, set
|
|
* up a pointer to a color table, and move CtlParam from a
|
|
* Direct Page location into an absolute location.
|
|
*
|
|
*
|
|
* Inputs: NONE
|
|
*
|
|
* Outputs: NONE
|
|
*
|
|
* External Refs: NONE
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
with CtlData
|
|
|
|
;
|
|
; Check to see if the Control Manager is sending us a 'RecSize' call. If it
|
|
; is, then we cannot rely on the validity of the Control handle, as it has not
|
|
; yet been allocated and is essentially garbage. Since we do not know what it
|
|
; points to, we don't want to read from it, as it may actually accidentally
|
|
; point to something dangerous, like the IWM I/O locations!!! So if we detect
|
|
; a RecSize code, skip over this routine.
|
|
;
|
|
lda <CtlCode ; is this a RecSize call?
|
|
cmp #recSize
|
|
beq done ; yes - skip this whole routine
|
|
|
|
;
|
|
; Copy the value in CtlParam into a local location -- off of the direct page.
|
|
; We do this for convenience. We may need to pass a pointer to CtlParam to
|
|
; a toolbox routine, but you can't do that for a direct page location. The
|
|
; number assiciated with a direct page location is really an offset off of the
|
|
; base specified by the Direct Page register; it is NOT an absolute memory
|
|
; location. So that we can conveniently use 'PushLong #location' if we need
|
|
; to, I copy CtlParam to a non-direct page location.
|
|
;
|
|
lda <CtlParam
|
|
sta theParam
|
|
lda <CtlParam+2
|
|
sta theParam+2
|
|
|
|
ldy #2 ; get a handy pointer to the CtlRec
|
|
lda [<theCtlHandle],y
|
|
sta <CtlPtr+2
|
|
lda [<theCtlHandle]
|
|
sta <CtlPtr
|
|
|
|
ldy #octlRect+6 ; copy the control rect over to the
|
|
ldx #6 ; local variable.
|
|
loop lda [<CtlPtr],y
|
|
sta myCtlRect,x
|
|
dey
|
|
dey
|
|
dex
|
|
dex
|
|
bpl loop
|
|
|
|
;
|
|
; The following values are used by Snap2Grid. However, Snap2Grid can be
|
|
; called with an invalid Direct Page, so we copy them out the control
|
|
; record (which is pointed to by a pointer in our Direct Page) and into
|
|
; some absolute locations that we can get to at all times.
|
|
;
|
|
ldy #oCtlGridX ; get the X and Y spacings out of the
|
|
lda [<CtlPtr],y ; control record and into some local
|
|
sta myCtlGridX ; storage for easy handling.
|
|
|
|
ldy #oCtlGridY
|
|
lda [<CtlPtr],y
|
|
sta myCtlGridY
|
|
|
|
; Check the color table pointer. If it is non-zero, install it as the
|
|
; pointer to the color table we'll be using. If not, then install a
|
|
; pointer to a default color table.
|
|
|
|
ldy #octlColor ; Get the pointer to the color
|
|
lda [<CtlPtr],y ; table in the control record.
|
|
sta ColorPtr ; Save it to a local pointer.
|
|
iny
|
|
iny
|
|
lda [<CtlPtr],y
|
|
sta ColorPtr+2
|
|
ora ColorPtr ; is it a NULL pointer?
|
|
bne done ; no, so use it.
|
|
|
|
lda #StdColorTable ; yes, install my own color table.
|
|
sta ColorPtr
|
|
lda #^StdColorTable
|
|
sta ColorPtr+2
|
|
|
|
done
|
|
rts
|
|
|
|
ENDP
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
SetCtlRect PROC
|
|
*
|
|
* Description: This routine is called when the control's bounding
|
|
* rectangle has been changed and needs to be written back
|
|
* out to the control record.
|
|
*
|
|
*
|
|
* Inputs: NONE
|
|
*
|
|
* Outputs: NONE
|
|
*
|
|
* External Refs: NONE
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
with CtlData
|
|
|
|
ldy #octlRect+6 ; get an offset into the control rec.
|
|
ldx #6 ; index to my local record.
|
|
loop
|
|
lda myCtlRect,x
|
|
sta [<CtlPtr],y
|
|
dey
|
|
dey
|
|
dex
|
|
dex
|
|
bpl loop
|
|
|
|
rts
|
|
|
|
ENDP
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
SetMyPen PROC
|
|
*
|
|
* Description: We want our control to look good in both 320 and 640 mode.
|
|
* Because vertical lines are thinner in 640 than 320, its a
|
|
* good idea to draw them doubly thick just so they can be
|
|
* seen. This routine will determine what mode we are in and
|
|
* adjust the pen accordingly.
|
|
*
|
|
*
|
|
* Inputs: NONE
|
|
*
|
|
* Outputs: NONE
|
|
*
|
|
* External Refs: NONE
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
with CtlData
|
|
|
|
pha ; we base pen width on the MasterSCB
|
|
_GetMasterSCB
|
|
pla
|
|
and #$0080 ; check the mode bit
|
|
beq pen320 ; we are in 320 mode - go push a 1
|
|
|
|
PushWord #2 ; in 640 mode - push on a 2 width
|
|
bra setpn
|
|
|
|
pen320 PushWord #1 ; in 320 mode - push on a 1 width
|
|
|
|
setpn ; width is 1 or 2
|
|
PushWord #1 ; Height is always 1
|
|
_SetPenSize
|
|
|
|
rts
|
|
ENDP
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
CalcCorners PROC
|
|
*
|
|
* Description: This routine calculates the rectangles for all of the
|
|
* little knobs that are used to grow the control. They are
|
|
* stored locally - not with the control record - and so need
|
|
* to be calculated every time we need to check for hits or
|
|
* to draw the control.
|
|
*
|
|
*
|
|
* Inputs: NONE
|
|
*
|
|
* Outputs: knobXXX, FrameHeight, FrameWidth variables are initialized.
|
|
*
|
|
* External Refs: NONE
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
with CtlData
|
|
|
|
top equ 0 ; alias these to something a little
|
|
left equ 2 ; more descriptive.
|
|
bottom equ 4
|
|
right equ 6
|
|
|
|
; Get the size of the knobs. The height and width are stored in the CtlValue
|
|
; field in a packed format. This unpacks them and stores them locally for
|
|
; ease of access.
|
|
|
|
ldy #octlValue
|
|
lda [<CtlPtr],y
|
|
and #$00FF
|
|
sta FrameHeight
|
|
lda [<CtlPtr],y
|
|
xba
|
|
and #$00FF
|
|
sta FrameWidth
|
|
|
|
;
|
|
; We "assembly line" the initialization of the knob rectangles. Instead
|
|
; of calculating just one knob at a time, we do a few of them all at the
|
|
; same time. Here we initialize the tops and bottoms of the 3 top knobs.
|
|
|
|
lda myCtlRect+top
|
|
sta knobUL+top
|
|
sta knobTop+top
|
|
sta knobUR+top
|
|
clc
|
|
adc FrameHeight
|
|
sta knobUL+bottom
|
|
sta knobTop+bottom
|
|
sta knobUR+bottom
|
|
|
|
;
|
|
; Initialize the lefts and rights of the three left knobs.
|
|
;
|
|
lda myCtlRect+left
|
|
sta knobUL+left
|
|
sta knobLeft+left
|
|
sta knobLL+left
|
|
clc
|
|
adc FrameWidth
|
|
sta knobUL+right
|
|
sta knobLeft+right
|
|
sta knobLL+right
|
|
|
|
;
|
|
; Initialize the tops and bottoms of the three bottom knobs.
|
|
;
|
|
lda myCtlRect+bottom
|
|
sta knobLL+bottom
|
|
sta knobBottom+bottom
|
|
sta knobLR+bottom
|
|
sec
|
|
sbc FrameHeight
|
|
sta knobLL+top
|
|
sta knobBottom+top
|
|
sta knobLR+top
|
|
|
|
;
|
|
; Initialize the lefts and rights of the three right knobs.
|
|
;
|
|
lda myCtlRect+right
|
|
sta knobUR+right
|
|
sta knobRight+right
|
|
sta knobLR+right
|
|
sec
|
|
sbc FrameWidth
|
|
sta knobUR+left
|
|
sta knobRight+left
|
|
sta knobLR+left
|
|
|
|
;
|
|
; At this point, the 4 corner knobs have been completely initialized.
|
|
; If we are going to be using the edge knobs, then we'll have to do
|
|
; some extra math. However, if we aren't, then we'll skip over the
|
|
; math.
|
|
|
|
ldy #octlFlag
|
|
lda [<CtlPtr],y
|
|
and #knobEdgeMask
|
|
beq done
|
|
|
|
; Do extra setup for edge knobs
|
|
;
|
|
; First, get top and bottom coordinates for the side edges:
|
|
;
|
|
; top = (myCtlRect.top + myCtlRect.bottom - FrameHeight)/2
|
|
; bot = (myCtlRect.top + myCtlRect.bottom + FrameHeight)/2
|
|
|
|
clc
|
|
lda myCtlRect+top
|
|
adc myCtlRect+bottom
|
|
pha
|
|
adc FrameHeight
|
|
lsr a
|
|
sta knobLeft+bottom
|
|
sta knobRight+bottom
|
|
pla
|
|
sec
|
|
sbc FrameHeight
|
|
lsr a
|
|
sta knobLeft+top
|
|
sta knobRight+top
|
|
|
|
;
|
|
; Now perform similar calculations for the left and right sides
|
|
; of the top and bottom edge knobs.
|
|
;
|
|
clc
|
|
lda myCtlRect+left
|
|
adc myCtlRect+right
|
|
pha
|
|
adc FrameWidth
|
|
lsr a
|
|
sta knobTop+right
|
|
sta knobBottom+right
|
|
pla
|
|
sec
|
|
sbc FrameWidth
|
|
lsr a
|
|
sta knobTop+left
|
|
sta knobBottom+left
|
|
|
|
done
|
|
rts
|
|
ENDP
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
Snap2Grid PROC
|
|
*
|
|
* Description: This control defproc lets the application optionally create
|
|
* an invisible grid based on local coordinates. When this is
|
|
* done, the 4 corners of the control are always aligned to
|
|
* the coordinates of this grid. This occurs when we drag or
|
|
* resize the control, or call MoveControl. Snap2Grip is the
|
|
* routine that ensures we are on the grid.
|
|
*
|
|
*
|
|
* Inputs: A = low word of pointer to rectangle to fix
|
|
* X = high word
|
|
*
|
|
* Outputs: rectangle is modified in place.
|
|
*
|
|
* External Refs: NONE
|
|
*
|
|
* Entry Points: NONE
|
|
*
|
|
*******************************************************************************
|
|
with CtlData
|
|
|
|
oldD equ 1
|
|
oldB equ oldD+2
|
|
rectPtr equ oldB+1
|
|
|
|
;
|
|
; We are going to use a local direct page here. This is because Snap2Grid is
|
|
; called by my routine that draws the control's recangle as it is being
|
|
; dragged. When that happens, we are not using our normal direct page, and
|
|
; hence can't use any of the values or work locations there. So we set up
|
|
; another one with it's own workspace.
|
|
;
|
|
phx ; save the pointer to the rectangle
|
|
pha
|
|
|
|
phb ; save the caller's data bank register
|
|
phd ; save the caller'd direct page reg.
|
|
|
|
phk ; switch data bank to program bank
|
|
plb
|
|
|
|
tsc ; switch direct page to stack pointer
|
|
tcd
|
|
|
|
|
|
;
|
|
; WhchGridYX is used to help generalize this routine. We support different
|
|
; spacings in the X and Y directions of the grid. As we loop through all 4
|
|
; coordinates of the rectangle, we want to make sure that we are using the
|
|
; correct spacing. 'whichGridYX' holds flags that tell us when to use X and
|
|
; when to use Y spacing (0 = use Y spacing; 1 = use X spacing).
|
|
;
|
|
lda #%0101 ; Set up some indices into GridYX
|
|
sta whichGridYX
|
|
|
|
;
|
|
; Fix the coordinates by using the following method:
|
|
;
|
|
; 1. Get the difference between the coordinate we are examining and
|
|
; the next lowest grid location:
|
|
;
|
|
; z = coordinate mod GridSize
|
|
;
|
|
; 2. Z tells how far away from the next lowest grid line
|
|
; the coordinate we are looking at is, so subtracting that
|
|
; value will put the coordinate on the grid.
|
|
;
|
|
; coordinate := coordinate - z
|
|
;
|
|
; 3. However, this is simply truncating, and I don't like the
|
|
; way that feels when resizing the control. So lets add an
|
|
; instruction so that it ROUNDS instead.
|
|
;
|
|
; if z > GridSize/2 then
|
|
; coordinate := coordinate + GridSize
|
|
;
|
|
|
|
ldy #6 ; init our loop index
|
|
Loop
|
|
sty YSave
|
|
|
|
lda whichGridYX ; do we now use X or Y grid spacing?
|
|
and #%0001
|
|
beq UseY
|
|
lda myCtlGridX
|
|
bra UseIt
|
|
UseY
|
|
lda myCtlGridY
|
|
|
|
; we now have the gridsize in the Acc
|
|
UseIt
|
|
cmp #2 ; Is it 0 or 1? If so, then skip over
|
|
blt ShortCircuit ; dividing routine.
|
|
sta GridSize ; save this for the divide later.
|
|
|
|
pha ; push space on stack for the result
|
|
pha ; of the divide we are going to do.
|
|
|
|
lda [<rectPtr],y ; push on the coordinate we are
|
|
pha ; adjusting as the Dividend
|
|
PushWord GridSize ; push this on as the divisor
|
|
_UDivide ; unsigned divide
|
|
pla ; quotient - we don't want it.
|
|
PullWord Remainder ; remainder is 'z' - Keep it!
|
|
|
|
ldy YSave ; get my coordinate index back.
|
|
lda [<rectPtr],y ; get the coordinate to change
|
|
sec
|
|
sbc Remainder ; change it
|
|
sta [<rectPtr],y ; save it back out
|
|
|
|
lda GridSize ; Make a GridSize/2
|
|
lsr a
|
|
cmp Remainder ; is remainder < GridSize/2?
|
|
bge ShortCircuit ; yes - so we're done
|
|
lda [<rectPtr],y ; no - so bump the coordinate
|
|
clc
|
|
adc GridSize
|
|
sta [<rectPtr],y
|
|
|
|
ShortCircuit lsr whichGridYX ; move the next index into place
|
|
dey ; bump down to the next coordinate
|
|
dey ; of the rectangle.
|
|
bpl Loop
|
|
|
|
Exit
|
|
pld ; restore caller's Direct Page reg.
|
|
plb ; restore data bank register
|
|
pla ; remove rect pointer
|
|
pla
|
|
rts ; all done - go bye-bye
|
|
|
|
whichGridYX ds.b 2
|
|
YSave ds.b 2
|
|
Remainder ds.b 2
|
|
GridSize ds.b 2
|
|
|
|
ENDP
|
|
|
|
EJECT
|
|
*******************************************************************************
|
|
*
|
|
FindPart PROC
|
|
*
|
|
* Description: This routine is called to find out exactly which part of
|
|
* the control we clicked in. It first checks to see if we
|
|
* clicked in any of the grow knobs. If so, then it returns
|
|
* an 'internal partcode' telling the calling routine which
|
|
* knob was clicked in. If a knob wasn't clicked in, a check
|
|
* is made to see if we clicked on the frame. If we are
|
|
* allowed to click in the interior, a check is made to see
|
|
* if we clicked there, too.
|
|
*
|
|
*
|
|
* Inputs: NONE
|
|
*
|
|
* Outputs: A = internal partcode of part hit (1-10)
|
|
*
|
|
* External Refs:
|
|
import CalcCorners
|
|
*
|
|
* Entry Points:
|
|
entry TestFrame ; called by myTestCtl
|
|
*
|
|
*******************************************************************************
|
|
with CtlData
|
|
|
|
jsr CalcCorners
|
|
|
|
;
|
|
; We first check to see if the mouse was clicked in any of the knobs. We do
|
|
; this by assuming a knob was clicked in, and then checking to see if that was
|
|
; true. If so, we leave here with the partcode we assumed. If not, we loop
|
|
; through and check all of the other knobs. If none of the knobs was clicked
|
|
; in, we see if the frame was clicked on.
|
|
|
|
ldx #LeftPart ; get last knob's part code
|
|
ldy #7*8 ; point to last knob's rect
|
|
|
|
loop
|
|
phx ; save partcode we're checking for...
|
|
phy ; and the rect's pointer
|
|
|
|
pha ; space for _PtInRect result
|
|
PushLong #theParam ; push on the point to check
|
|
lda #^knobUL ; create a pointer to the rect
|
|
pha
|
|
clc ; Bumping just the low byte is OK
|
|
tya ; unless the GS suddenly lets
|
|
adc #knobUL ; code segments cross bank
|
|
pha ; boundaries
|
|
_PtInRect
|
|
pla ; get result of PtInRect
|
|
ply ; retrieve rectangle index
|
|
plx ; retrieve part code
|
|
cmp #0 ; did we score a hit?
|
|
bne InKnob ; yes, return with the part code
|
|
dex ; move down to next partcode
|
|
sec ; move down to next rectangle
|
|
tya
|
|
sbc #8
|
|
tay
|
|
bpl loop ; keep going until rect index < 0
|
|
|
|
bra TestFrame ; not in knobs - try frame
|
|
|
|
;
|
|
; We just scored a hit on one of the knobs, and X holds the knob number.
|
|
; However, the application may not have corner or edge knobs active. So
|
|
; if we clicked on an inactive knob, have to check for that and return
|
|
; 'inFrame' instead of a knob partcode.
|
|
;
|
|
InKnob
|
|
ldy #octlFlag ; are corner knobs active?
|
|
lda [<CtlPtr],y
|
|
and #knobCornerMask
|
|
bne ckEdge ; yes - so pass this code on.
|
|
|
|
txa ; Corners not allowed. Did we hit one?
|
|
lsr a
|
|
bcs RetFramePart ; yes, so return click on Frame instead
|
|
|
|
ckEdge
|
|
ldy #octlFlag ; are edge knobs active?
|
|
lda [<CtlPtr],y
|
|
and #knobEdgeMask
|
|
bne done ; yes - so return this code
|
|
|
|
txa ; Edges not allowed. Did we hit one?
|
|
lsr a
|
|
bcs TestFrame ; no, so pass this code on.
|
|
RetFramePart
|
|
ldx #FramePart ; yes, so return click on Frame instead
|
|
done
|
|
txa ; put the part code in the Acc
|
|
rts
|
|
|
|
TestFrame
|
|
|
|
; First test to see if it is within the Control's rectangle. It should
|
|
; be, but let's check anyway...
|
|
|
|
pha
|
|
PushLong #theParam
|
|
PushLong #myCtlRect
|
|
_PtInRect
|
|
pla
|
|
beq NotInFrame ; no in the frame. Signal noPart
|
|
|
|
; Now see if we differentiate between the frame and the interior
|
|
|
|
ldy #octlFlag
|
|
lda [<CtlPtr],y
|
|
and #dragIntMask
|
|
bne RetFramePart ; nope - everything drags
|
|
|
|
; Yes we do. Now see if we hit the frame fair and square. Inset the
|
|
; control's bounding rectangle by the size of the knobs that are on
|
|
; it to create an inner rectangle. If we fall between those two
|
|
; rectangles, then I say that you have landed on the frame. If we
|
|
; got this far, then we know that we are within the outer rectangle.
|
|
; Now see if we are outside of the inner rectangle.
|
|
|
|
ldx #6 ; make a copy of the control rect
|
|
CopyLoop lda myCtlRect,x ; so that we can reduce it.
|
|
sta innerRect,x
|
|
dex
|
|
dex
|
|
bpl CopyLoop
|
|
|
|
PushLong #innerRect ; push on pointer to the rect to inset
|
|
PushWord FrameWidth ; push on the amounts to inset it by
|
|
PushWord FrameHeight ; (these vals inited by CalcCorners)
|
|
_InsetRect
|
|
|
|
pha ; see if we are outside of the inner
|
|
PushLong #theParam ; rectangle
|
|
PushLong #innerRect
|
|
_PtInRect
|
|
|
|
pla ; check the result
|
|
beq RetFramePart ; we were between rects!
|
|
|
|
NotInFrame lda #noPart ; Not *exactly* on the frame.
|
|
rts
|
|
|
|
innerRect ds.b 8
|
|
|
|
ENDP
|
|
|
|
End
|
|
|