*******************************************************************************
*
* Custom Control -- Version 3.0
*
* (C)  Copyright Apple Computer, Inc. 1988-1990
* All rights reserved.
*
* Developer Technical Support Apple II Sample Code
*
* by Keith Rollin
*
* The Custom control is a rectangle with little knobs on the corners and
* sides. The knobs can be dragged to change the size of the rectangle.
* Clicking on the frame will allow you to move the whole thing.
*
* The application sample shows how to create and use the control. It is used
* to size and position a Simple Button control.
*
*******************************************************************************
**********************************************************************
*     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
	PRINT NOGEN,NOHDR

	case   on

	STRING ASIS

	PRINT PUSH,OFF
	INCLUDE 'M16.Util'
	INCLUDE 'M16.ProDOS'
	INCLUDE 'M16.MiscTool'
	INCLUDE 'M16.QUICKDRAW'
	INCLUDE 'E16.Quickdraw'
	INCLUDE 'M16.MEMORY'
	INCLUDE 'E16.Memory'
	INCLUDE 'M16.EVENT'
	INCLUDE 'E16.EVENT'
	INCLUDE 'M16.LOCATOR'
	INCLUDE 'M16.Menu'
	INCLUDE 'M16.Control'
	INCLUDE 'E16.Control'
	INCLUDE 'M16.Window'
	INCLUDE 'E16.Window'
	INCLUDE 'M16.Dialog'
	INCLUDE 'E16.Dialog'
	INCLUDE 'M16.LineEdit'
	INCLUDE 'M16.IntMath'
	INCLUDE 'M16.Scrap'
	INCLUDE 'M16.Desk'
	INCLUDE 'M16.Texttool'
	PRINT POP

*******************************************************************************
*
*    Equates used in this program.
*
*******************************************************************************
DPHandle	equ 0	; Handle to Tool Direct Page area
DPPointer	equ DPHandle+4	; Pointer to Tool Direct Page area
deref	equ DPPointer+4	; Temporary Handle dereference area
Ctl1Ptr	equ deref+4
Ctl2Ptr	equ Ctl1Ptr+4
Control1	equ Ctl2Ptr+4
Control2	equ Control1+4

ScreenMode	equ mode640	; used for _QDStartup
ScreenWidth	equ 640	; used for _EMStartup


	EJECT
*******************************************************************************
*
Main	PROC
*
* Description:	This is the main routine. It calls routines to Initialize
*	the tools, initialize application specific data, run the
*	main EventLoop, close the application, and close the tools.
*	Then it calls the ProDOS Quit command.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:
	import InitTools
	import InitApp
	import EventLoop
	import CloseApp
	import CloseTools
	import QuitParms
*
* Entry Points:	NONE
*
*******************************************************************************

	jsr InitTools
	jsr InitApp

	_ShowCursor

	jsr EventLoop

	jsr CloseApp
	jsr CloseTools

	_Quit QuitParms

	ENDP

	EJECT
*******************************************************************************
*
Globals	Record
*
* Description:	Holder of all of our data.
*
*
* Inputs:	N/A
*
* Outputs:	N/A
*
* External Refs:	
	import doUpdate	; to update windows
*
* Entry Points:
	export QuitParms	; used by Main
*
*******************************************************************************
*
* Standard global data
*
*******************************************************************************

TitleString	str 'Custom Control Example Program'
AutString	str 'By Keith Rollin Apple DTS -- Version 3.0'
VersString	str 'Copyright (c) 1988-1990 Apple Computer'

MenuHeight	ds.b 2	; Stored height of menu bar
MyID	ds.b 2	; Application ID
MyDP	ds.b 2	; My direct page storage

QuitFlag	ds.W 1
QuitParms	dc.l 0	; Pathname of next app
	dc.w $00	; flags

EventRecord
EventWhat	ds.b 2
EventMessage	ds.b 4
EventWhen	ds.b 4
EventWhere	ds.b 4
EventModifiers	ds.b 2
TaskData	ds.b 4
TaskMask	dc.l $0000FFFF

	EJECT
*******************************************************************************
*
* Application specific global data
*
*******************************************************************************

; This is a list of pointers to the text that is used to create our menus. It
; is used by InitApp to find all of the menu templates and use them to create
; our menubar. This loop loads MenuPtrLen-4 into an index, gets the
; corresponding menu template pointer in this table, and uses that in a
; NewMenu call. It then decrements the index by 4, and repeats the procees
; until the index is negative.

MenuPtr	dc.l AppMenu
	dc.l FileMenu
	dc.l EditMenu
MenuPtrLen	equ *-MenuPtr


; Menu list: menu items should be numbered consecutivly starting from 250.
; As a convention, use 256 as about and 257 as Quit.

AppMenu	dc.b '$$@\XN1',$00
	dc.b '--About Custom Control...\N256V',$00
	dc.b '.'
FileMenu	dc.b '$$  File  \N2',$00
	dc.b '--Hide Sizer\N259',$00
	dc.b '--Show Sizer\N258D',$00
	dc.b '--Close\N255DV',$00
	dc.b '--Quit\N257*Qq',$00
	dc.b '.'
EditMenu	dc.b '$$  Edit  \N3',$00
	dc.b '--Undo\N250*ZzVD',$00
	dc.b '--Cut\N251*XxD',$00
	dc.b '--Copy\N252*CcD',$00
	dc.b '--Paste\N253*VvD',$00
	dc.b '--Clear\N254D',$00
	dc.b '.'

theWindow	ds.b 4


WindowTitle	str '  Custom Control  '

Stripes	dc.w $0000	; Black frame
	dc.w $0f00	; Inact TBcolor, Inact TColor, Tcolor
	dc.w $020f	; Pattern, Pattern color, BG color
	dc.w $0000	; Frame growbox unselcted/selected
	dc.w $00f0	; infobar color (white)

WindData	dc.w WEnd-WindData
	dc.w fTitle+fMove+fVis+fCtlTie
	dc.l WindowTitle	; Ptr to title
	dc.l $0	; RefCon
	dc.w 0,0,0,0	; Full Size (0= default)
	dc.l Stripes	; Color Table Pointer
	dc.w 0,0	; Vertical/Horizontal origin
	dc.w 0,0	; Data area height,	width
	dc.w 0,0	; Max Cont height, width
	dc.w 0,0	; Pixels to scroll vert'ly, horiz'ly
	dc.w 0,0	; Pixels to page vert'ly, horiz'ly
	dc.l 0	; Information bar refcon.
	dc.w 0	; Info bar height
	dc.l 0	; DefProc.
	dc.l 0	; Routine to draw info. bar.
	dc.l doUpdate	; Routine to draw content.
	dc.w 30,40,160,400	; Size and position
	dc.l $FFFFFFFF	; Plane to put window up in (topmost).
	dc.l 0	; Address of window record (0 to alloc)
WEnd
	ENDR

	EJECT
*******************************************************************************
*
InitApp	PROC
*
* Description:	Perform any application specific initialization.
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:
	import BoxProc
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	stz QuitFlag

	pha
	pha
	PushLong #WindData
	_NewWindow
	PullLong theWindow	; Pull off the window pointer

; Create the two controls that we will be using in this demo. They are a
; custom control, and a simply button that will be resized and moved with
; the custom control. However, it is important that they be created in the
; right order. Since they will be lying right on top of each other, it is not
; apparent which one we want to select when we click on one of them. In cases
; like this, where a mouse click is on top of two controls, the Control
; Manager selects the one that was created first. So we create the custom
; control first.

	pha	; space for result
	pha
	PushLong theWindow
	PushLong #theRect
	PushLong #0	; no title
	PushWord #%111	; vis, int will drag, corners & edges
	PushWord #$0503	; Width = 5/Height = 3
	PushLong #CtrlData	; Pointer to additional data
	PushLong #BoxProc	; DefProc
	PushLong #0	; refcon
	PushLong #0	; std color table
	_NewControl
	PullLong Control1

; It is possible that the rectangle that was used to create the above
; control is no longer the rectangle that is being used. This is because
; of the feature that aligns the corners of the control to the grid.
; In order to make the next control fall inside of the above control, get
; the CtlRect from its record, and use that when creating the simple
; button below.

	ldy #2	; dereference the Control handle
	lda [Control1],y	; to get a pointer to the control
	sta Ctl1Ptr+2	; record into 'Ctl1Ptr'
	lda [Control1]
	sta Ctl1Ptr

	ldy #octlRect+6	; now copy the control's rectangle
	ldx #6	; into 'theRect'
loop0010	lda [Ctl1Ptr],y
	sta theRect,x
	dey
	dey
	dex
	dex
	bpl loop0010

; now that that is done, we can create the simple button control

	pha	; space for result
	pha
	PushLong theWindow
	PushLong #theRect
	PushLong #Title
	PushWord #0
	PushWord #0
	PushLong #0
	PushLong #simpleProc
	PushLong #0	; refcon
	PushLong #0	; std color table
	_NewControl
	PullLong Control2

	rts

theRect	dc.w 50,140,110,300
Title	str 'Move/Resize Me'
CtrlData	dc.w 10	; min Y
	dc.w 10	; min X
	dc.w 100	; max Y
	dc.w 200	; max X
	dc.w 16	; grid Y
	dc.w 32	; grid X
	ENDP

	EJECT
*******************************************************************************
*
CloseApp	PROC
*
* Description:	Close down things. This disposes of all items and memory
*	that we allocated.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	rts
	ENDP

	EJECT
*******************************************************************************
*
EventLoop	PROC
*
* Description:	Main Event Loop. Handle things until user selects Quit.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:
	import MenuSelect
	import Ignore
	import doUpdate
	import InContent
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

maxEvent	equ wInactMenu

	pha	; Push on space for TaskMaster result
	PushWord #everyEvent ; GetNextEvent mask
	PushLong #EventRecord ; Pointer to Event Record
	_TaskMaster

	pla	; Get TaskMaster result
	beq EventLoop	; Remove if you want to use null events
	cmp #maxEvent+1	; is the event number in range?
	bge EventLoop
	asl A	; Turn it into an index
	tax
	jsr (TaskTable,x)	; Call appropriate event handler

	lda QuitFlag	; Quit selected?
	beq EventLoop	; no - keep looping

	rts	; yes- leave the program

TaskTable	dc.w Ignore	; 0 Null
	dc.w Ignore	; 1 MouseDown
	dc.w Ignore	; 2 MouseUp
	dc.w Ignore	; 3 KeyDown
	dc.w Ignore	; 4 undefined
	dc.w Ignore	; 5 AutoKey
	dc.w Ignore	; 6 Update
	dc.w Ignore	; 7 undefined
	dc.w Ignore	; 8 Activate
	dc.w Ignore	; 9 Switch
	dc.w Ignore	; 10 Desk accessory
	dc.w Ignore	; 11 Device driver
	dc.w Ignore	; 12 ap
	dc.w Ignore	; 13 ap
	dc.w Ignore	; 14 ap
	dc.w Ignore	; 15 ap
	dc.w Ignore	; TASK 0 indesk
	dc.w MenuSelect	; TASK 1 in menuBar
	dc.w Ignore	; TASK 2 in system window
	dc.w InContent	; TASK 3 in content
	dc.w Ignore	; TASK 4 in Drag
	dc.w Ignore	; TASK 5 in grow
	dc.w Ignore	; TASK 6 in goaway
	dc.w Ignore	; TASK 7 in zoom
	dc.w Ignore	; TASK 8 in info bar
	dc.w MenuSelect	; TASK 9 in special	menu
	dc.w Ignore	; TASK 10 in NDA
	dc.w Ignore	; TASK 11 in frame
	dc.w Ignore	; TASK 12 in drop

	ENDP

	EJECT
*******************************************************************************
*
MenuSelect	PROC
*
* Description:	This routine is called when TaskMaster returns a menu
*	event. It takes the menu item that was hit and calculates
*	an offset into the menu dispatch table. It then calls that
*	routine and unhilites the menu when it is done.
*
* Inputs:	TaskData holds menu item selected.
*
* Outputs:	NONE
*
* External Refs:
	import Ignore
	import doAbout
	import doQuit
	import ShowSizer
	import HideSizer
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	lda TaskData	; Get the ID of the menu item selected.
	sec	; Turn it into an index by subtracting
	sbc #250	; the starting ID number (25) and mul-
	asl a	; tiplying by 2 (each table entry con-
	tax	; sists of 2 bytes).
	jsr (MenuTable,x)	; Call the routine behind it.

	PushWord #0	; Routine done - unhilite the menubar.
	PushWord TaskData+2
	_HiLiteMenu

	rts

MenuTable	dc.w Ignore	; undo
	dc.w Ignore	; cut
	dc.w Ignore	; copy
	dc.w Ignore	; paste
	dc.w Ignore	; clear
	dc.w Ignore	; close
	dc.w doAbout
	dc.w doQuit
	dc.w ShowSizer
	dc.w HideSizer
	ENDP

	EJECT
*******************************************************************************
*
Ignore	PROC
*
* Description:	Called when I want to ignore an event.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************

	rts
	ENDP

	EJECT
*******************************************************************************
*
doUpdate	PROC
*
* Description:	Called by TaskMaster to update a window's contents.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	with Globals
	
	pha
	pha
	_GetPort
	_DrawControls

	rtl
	ENDP

	EJECT
*******************************************************************************
*
InContent	PROC
*
* Description:	Handle clicks within the content region of a window. In
*	this demo, we want to see if we have clicked on either of
*	the controls. We do this by calling FindControl. If
*	FindControl tells us that we clicked on a control, then we
*	want to track the actions of that control as we move the
*	mouse. Calling TrackControl will do this until the use
*	lift up on the mouse button. Finally, if the control we
*	were tracking was the 'sizer' custom control, we want to
*	resize/move the simple button that was associated with it.
*	So we hide the button, change its bounding rectangle, and
*	show it again in its new location.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	with Globals
	
	pha
	PushLong #theControl
	PushLong EventWhere
	PushLong theWindow
	_FindControl
	pla	; pull off the part code
	bne TrackIt	; hit a control
	brl done

TrackIt	pha
	PushLong EventWhere
	PushLong #0	; no action Proc
	PushLong theControl
	_TrackControl
	pla

	cmp #$A0	; did we track the Sizer?
	bne done	; no, so don't move anything

	PushLong Control2	; hide the simple button
	_HideControl

	PushLong Control1	; hide the Sizer
	_HideControl

	ldy #2	; Get Control's pointer and put it
	lda [Control1],y	; into a Direct Page location
	sta Ctl1Ptr+2
	lda [Control1]
	sta Ctl1Ptr	; 'Ctl1Ptr' points to the Sizer.

	ldy #2	; Do the exact same thing with the
	lda [Control2],y	; simple button.
	sta Ctl2Ptr+2	
	lda [Control2]
	sta Ctl2Ptr	; 'Ctl2Ptr' points to the simple button

	ldy #octlRect	; Now copy the bounding rectangle of
loop	lda [Ctl1Ptr],y	; the Sizer into the bounding rectangle
	sta [Ctl2Ptr],y	; of the button. When we next show the
	iny	; button, it will have the same size
	iny	; and location as the Sizer.
	cpy #octlRect+8
	bne loop

	PushLong Control2	; Now Show Them both
	_ShowControl

	PushLong Control1
	_ShowControl

done
	rts

theControl	ds.b 4

	ENDP

	EJECT
*******************************************************************************
*
ShowSizer	PROC
*
* Description:	Call _ShowControl to...well...uh, show the control. Disable
*	the "Show Sizer" menu item and enable the "Hide Sizer" menu
*	item.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	PushLong Control1
	_ShowControl

	PushWord #258	; Disable the Show menu item
	_DisableMItem

	PushWord #259	; Enable the Hide Menu item
	_EnableMItem

	rts
	ENDP


	EJECT
*******************************************************************************
*
HideSizer	PROC
*
* Description:	Call _HideControl to hide the control. Enable the "Show
*	Sizer" menu item and disable the "Hide Sizer" menu item.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	PushLong Control1
	_HideControl

	PushWord #258	; Enable the Show menu item
	_EnableMItem

	PushWord #259	; Disable the Hide Menu item
	_DisableMItem

	rts
	ENDP

	include 'BoxCtrl.Stds.aii'
	include 'BoxCtrl.DefProc.aii'

	END

