supermario/bin/MPW-3.2.3/Interfaces/AStructMacs/Sample.a
2019-06-29 22:17:03 +08:00

452 lines
16 KiB
Plaintext

TITLE 'Sample - A small sample application using Structured Macros'
* File Sample.a using structured program macros
* Copyright Apple Computer, Inc. 1985, 1986, 1987, 1988, 1989, 1990
* All rights reserved.
* Sample -- A small sample application written in MPW Assembler. It displays
* single, fixed-size window in which the user can enter and edit text.
* This is a translation of the Sample.a program in the Inside Macintosh
* documentaion. Some changes were made to illustrate some of the features of
* the MPW Assembler, but most comments and the order of the code is the same as
* the Pascal example.
* Note, this code assumes that the DEGUG switch available to the structured
* macros is OFF (the preset case), since DoCommand pops its return and
* parameter directly off the stack and doesn't know that with DEBUG set a
* LINK on A6 is generated!
* The PRINT directive turns off listing (if a listing is being generated using
* -l command line option) of the standard include files. The INCLUDEs bring in
* the equate and trap definitions needed by Sample. We could use the LOAD/DUMP
* facilities on these includes if we intended to assemble this program over and
* over again, but that would confuse the example here.
PRINT OFF
INCLUDE 'Traps.a'
INCLUDE 'ToolEqu.a'
INCLUDE 'QuickEqu.a'
INCLUDE 'SysEqu.a'
LOAD 'ProgStrucMacs.d'
LOAD 'FlowCtlMacs.d'
PRINT ON,NOGEN
TITLE 'Global Declarations for Sample'
*************
* Constants *
*************
appleID EQU 128 ; Resource IDs/menu IDs for Apple,
fileID EQU 129 ; File, and Edit menus
editID EQU 130
menuCount EQU 3 ; Total number of menus
windowID EQU 128 ; Resource ID for application'w window
undoCommand EQU 1 ; Menu item numbers identifying
cutCommand EQU 3 ; commands in Edit menu
copyCommand EQU 4
pasteCommand EQU 5
clearCommand EQU 6
aboutMeDLOG EQU 128 ; Resource ID for the "about" dialog
authorItem EQU 2 ; "About sample" dialog item numbers
languageItem EQU 3
*********
* Types *
*********
* To illustrate how the template type feature works the following templates are
* declared and used instead of the simple offsets defined in the equate files.
* By using these, the Assember source appromixates very closely the Pascal
* source for referencing the corresponding information. Perhaps someday we will
* have a set of "equate" files that define types just like Pascal USES units do!
Point RECORD 0 ; Point = RECORD CASE INTEGER OF
v DS.W 1 ; 1: (v: INTEGER;
h DS.W 1 ; h: INTEGER);
ORG v ; 2: (vh: ARRAY[1..2] OF INTEGER)
vh DS.L 1
ENDR ; END;
Rect RECORD 0 ; Rect = RECORD CASE INTEGER OF
top DS.W 1 ; 1: (top: INTEGER;
left DS.W 1 ; left: INTEGER;
bottom DS.W 1 ; bottom: INTEGER;
right DS.W 1 ; right: INTEGER);
ORG top ;
topLeft DS.L Point ; 2: (topLeft: Point;
botRight DS.L Point ; 3: (botRight: Point)
ENDR ; END;
BitMap RECORD 0 ; BitMap = RECORD
baseAddr DS.L 1 ; baseAddr: QDPtr;
rowBytes DS.W 1 ; rowBytes: INTEGER;
bounds DS.L Rect ; bounds: Rect
ENDR ; END;
EventRecord RECORD 0 ; EventRecord = RECORD
what DS.W 1 ; what: INTEGER;
message DS.L 1 ; message: LONGINT;
when DS.L 1 ; when: LONGINT;
where DS.L Point ; where: Point;
modifiers DS.W 1 ; modifiers: INTEGER
ENDR ; END;
EJECT
***********************
* QuickDraw's Globals *
***********************
* The following data module is used to define the QuickDraw global data area.
* -----------
QuickDraw RECORD ,DECREMENT
thePort DS.L 1
white DS.B 8
black DS.B 8
gray DS.B 8
ltGray DS.B 8
dkGray DS.B 8
arrow DS.B cursRec
screenBits DS.B BitMap
randSeed DS.L 1
ORG -grafSize
ENDR
**************************
* Global Data for Sample *
**************************
* This is the global data used by Sample. Both these and the QuickDraw data
* above are referenced through a WITH statetment at the beginning of the procs
* that use this data. Since the Assembler knows when it is referencing data
* in a data module (since they must be declared before they are accessed),
* and since such data can only be accessed based on A5, there is no need to
* explicitly specify A5 in any code which references the data (unless indexing
* is used). Thus, in this program we have omitted all A5 references when
* referencing the data.
GlobalData RECORD
appleMenuH DS.L 1 ; Handle to the Apple menu
fileMenuH DS.L 1 ; Handle to the File menu
editMenuH DS.L 1 ; Handle to the Edit menu
dragRect DS.L Rect ; Drag limits
txRect DS.L Rect ; TextEdit's limits
doneFlag DS.B 1 ; True if Quit command processed
myEvent DS.L EventRecord ; Current event info
wRecord DS.B windowSize ; The application window record
myWindow DS.L 1 ; Ptr to the application window
whichWindow DS.L 1 ; Current event's window
textH DS.L 1 ; TextEdit's text handle
mousePt DS.L Point ; Used to get current mouse point
iBeamHdl DS.L 1 ; Handle to the iBeam cursor
ENDR
TITLE 'SetupMenus - Set up menus and menu bar'
******************************************
* SetUpMenus - Set up menus and menu bar *
******************************************
* This is a code module used only during initialization. Note, just as in the
* Pascal version, this is a distinct code module. Also, since SetUpMenus is
* only called during initialization, there is no need to keep it loaded. So
* we will place SetUpMenus in its own segment (called "Initialize") and unload
* it after SetUpMenus returns.
SEG 'Init' ; This illustrates segmenting!
PROCEDURE SetUpMenus
BEGIN With=GlobalData
Call _GetRMenu:L(#appleID),(Pass,appleMenuH); Read Apple menu from rsrc file
Call _InsertMenu((A7):L, #0) ; Install Apple menu in menu bar
Call _AddResMenu(, #'DRVR':L) ; Add DA names to Apple menu
Call _GetRMenu:L(#fileID),(Pass,fileMenuH); Read File menu from rsrc file
Call _InsertMenu(, #0) ; Install File menu in menu bar
Call _GetRMenu:L(#editID),(Pass,editMenuH); Read Edit menu from rsrc file
Call _InsertMenu(, #0) ; Install Edit menu in menu bar
Call _DrawMenuBar ; Draw the menu bar
Return ; Exit
ENDP
TITLE 'ShowAboutMeDialog - Display the "About"...'
**********************************************
* ShowAboutMeDialog - Display the "About"... *
**********************************************
* This procedure is called from DoCommand when item #1 is selected from the
* apple menu list. It sets up a dialog box indicating the author and language
* of this sample program. The box remains until the user clicks the mouse on
* the continue button.
SEG ; Undo SEG done above
PROCEDURE ShowAboutMeDialog
VAR savePort: L, \ ; Port at the time of call
itemType: W, \ ; Returned by _GetDItem (not used)
itemHdl: L, \ ; Handle to the item
itemRect: Rect, \ ; Returned by _GetDItem (not used)
itemHit: W ; Part code
BEGIN Save=A3
theDialog: EQU A3 ; Dialog pointer
*
* Start here: create current grafPort, and allocate space for the dialog box
*
Call _GetPort(savePort(FP):A) ; Remember the current grafPort
Call _GetNewDialog:A(#aboutMeDLOG, NIL, -1:A) ;Create a new dialog
MOVE.L (A7),theDialog ; theDialog holds ptr to dialog info
Call _SetPort ; Set the current grafPort
*
* Fill in the dialog box with the proper author and language
*
Call _GetDItem(theDialog:L, #authorItem, itemType(FP):A, itemHdl(FP):A, \
itemRect(FP):A); Get dialog's author item info
Call _SetIText(itemHdl(FP):L, #'Nebur L. Ari':A); Update the author item
Call _GetDItem(theDialog:L, #languageItem, itemType(FP):A, itemHdl(FP):A, \
itemRect(FP):A); Get dialog's language info
Call _SetIText(itemHdl(FP):L, #'Assembler':A); Update the language item
*
* Wait for user to click the continue button
*
REPEAT#
Call _ModalDialog(NIL, itemHit(FP):A) ; Wait for the click...
UNTIL#.S itemHit(FP) EQ #okButton
*
* User is now satisfied -- let's get out of here!
*
Call _CloseDialog(theDialog:L); Close the dialog box
Call _SetPort(savePort(FP):L) ; Put original grafPort back
Return
ENDP
TITLE 'DoCommand - Execute a menu command'
***********************************************************************
* DoCommand - Execute command specified by the result of a MenuSelect *
***********************************************************************
* This is another code module which takes as a parameter the MenuSelect return
* value. It is next to the top of the stack just before the return address.
PROCEDURE DoCommand;
BEGIN With=GlobalData
return: EQU A6 ; The return address will be in A6
mResult: EQU D3 ; mResult will be kept in D3
theItem: EQU mResult ; LoWord(mResult) is mResult treated as a word
* The following defines some local data known only to this proc.
DATA ; Switch into local data section
name: DS.B 256 ; Desk accessory name string
CODE ; Switch back to code section
MOVEA.L (A7)+,return ; Pop return into A6
MOVE.L (A7)+,mResult ; Pop mResult parameter
MOVE.L mResult,D0 ; Case on menu ID in
SWAP D0 ; high-order word of mResult
Switch# D0
Case#.S appleID ; Apple menu processing
Call _GetItem(appleMenuH:L, theItem, name:A); Get DA name
IF# theItem EQ #1 THEN.S
Call ShowAboutMeDialog
ELSE#.S
Call _OpenDeskAcc:W(name:A),Pop
ENDIF#
Call _SetPort(myWindow:L); Restore app window as grafPort
Leave#.S ; Exit
Case#.S fileID ; File menu processing
ST doneFlag ; Set flag to Quit (caller tests)
Leave#.S ; Exit
Case#.S editID ; Edit menu processing
MOVE theItem,D1 ; if DA window is the active window
SUBQ #1,D1 ; SystemEdit requires item adjustment
Call _SysEdit:B(D1),CC ; Call Desk Mgr to handle editing command
; if DA window is the active window
IF# EQ THEN.S ; App window is active window
Switch# theItem ; Case on menu item (command) number
Case#.S cutCommand; Call TextEdit to handle command
Call _TECut(textH:L)
Leave#.S
Case#.S copyCommand
Call _TECopy(textH:L)
Leave#.S
Case#.S pasteCommand
Call _TEPaste(textH:L)
Leave#.S
Case#.S clearCommand
Call _TEDelete(textH:L)
EndS# ; of item case
ENDIF#
EndS# ; of editID case
Call _HiliteMenu(#0) ; Unhighlight menu item
JMP (return) ; Exit
ENDP
TITLE 'Sample - Main Program'
***********************************************
* Sample Main Program - Execution starts here *
***********************************************
* This is another code module. It is declared as the main code module which
* means execution will start here.
PROCEDURE Sample,Main=Y
BEGIN With=(QuickDraw,GlobalData) ; Cover our data areas
*
* Initialization
*
Call _InitGraf(thePort:A) ; Initialize QuickDraw
Call _InitFonts ; Initialize Font Manager
MOVE.L #$0000FFFF,D0 ; Discard any previous events
Call _FlushEvents ; FlushEvents(EventEvent, 0);
Call _InitWindows ; Initialize Window Manager
Call _InitMenus ; Initialize Menu Manager
Call _TEInit ; Initialize TextEdit
Call _InitDialogs(NIL) ; Initialize Dialog Manager
Call _InitCursor ; Make cursor an arrow
Call _GetCursor:L(#iBeamCursor),iBeamHdl; Get the iBeam cursor handle to
; use in the main ctl loop when
; cursor is in the window
Call SetUpMenus ; Set up menus and menu bar
Call _UnLoadSeg(SetUpMenus:A) ; Unload the SetUpMenus segment since we
; will never call it again
WITH screenBits.bounds
MOVE right,D0 ; Call QuickDraw to set dragging
SUBQ #4,D0 ; boundaries; ensure at least
MOVE bottom,D1 ; 4 by 4 pixels will remain visible
SUBQ #4,D1
Call _SetRect(dragRect:A, #4, #24, D0, D1)
ENDWITH
CLR.B doneFlag ; Flag to detect Quit command
Call _GetNewWindow:L(#windowID, wRecord:A, #-1:L),(Pass,myWindow); Put up app window
Call _SetPort() ; Set current grafPort to this window
MOVE.L thePort,A0 ; Rectangle for text in window
MOVE.L portRect+topLeft(A0),txRect.topLeft
MOVE.L portRect+botRight(A0),txRect.botRight
Call _InSetRect(txRect:A, #4, #0) ; Bring it in 4 pixels from left/right edges
Call _TENew:L(txRect:A, txRect:A),textH ; Prepare for receiving text
EJECT
*
* Main Event Loop
*
REPEAT#
Call _SystemTask ; Perform periodic actions defined for DAs
Call _FrontWindow:L,D0 ; Get ptr to the front window
IF# D0 EQ.L myWindow THEN.S ; Front window is my mindow
Call _GetMouse(mousePt:A); Is mouse pointing in my window ?
MOVEA.L myWindow,A0
Call _PtInRect:B(mousePt:L, portRect(A0):A),CC
IF# NE THEN.S ; Yes, use the iBeam cursor
MOVE.L iBeamHdl,A0
MOVE.L (A0),-(A7)
ELSE#.S ; No, use the arrow cursor
PEA arrow
ENDIF#
Call _SetCursor ; Set cursor to arrow or iBeam
Call _TEIdle(textH:L) ; Make vertical bar blink
ENDIF#
Call _GetNextEvent:B(#everyEvent, myEvent:A),CC; ToolBox Event Mgr
IF# NE THEN
Switch# myEvent.what,JmpTbl=Y,ChkRng=Y; Case on event type
Case# mButDwnEvt ; Mouse down event processing
Call _FindWindow:W(myEvent.where:L, whichWindow:A),D0
Switch# D0 ; Process according to where
Case#.S inMenuBar ; Menu bar: process command
Call _MenuSelect:L(myEvent.where:L)
Call DoCommand ; DoCommand(MenuSelect(myEvent.where));
Leave#.S
Case#.S inSysWindow ; Desk accessory window
Call _SystemClick(myEvent:A, whichWindow:L)
Leave#.S
Case#.S inDrag ; Title bar
Call _DragWindow(whichWindow:L, myEvent.where:L, dragRect:A)
Leave#.S
Case#.S inContent ; Body of application window
Call _FrontWindow:L,D0 ; Which is in front?
IF# D0 NE.L whichWindow THEN.S ; Not us!
Call _SelectWindow(whichWindow:L)
ELSE#.S ; If we are in front...
Call _GlobalToLocal(myEvent.where:A)
MOVE.L myEvent.where,-(A7)
MOVE myEvent.modifiers,D0
BTST #shiftKey,D0
SNE -(A7) ; Indicate if shift key is down
Call _TEClick(,,textH:L)
ENDIF#
EndS#
Leave#
Case# keyDwnEvt,autoKeyEvt ; Key down and Auto key event processing
BTST #CmdKey,myEvent.modifiers
IF# NE THEN.S ; If cmd key down, call Menu Mgr to learn which
Call _MenuKey:L(myEvent.message+2)
Call DoCommand ; Process the command key
ELSE#.S ; If not a command key...
Call _TEKey(myEvent.message+2, textH:L); ...pass char to TE
ENDIF#
Leave#.S
Case# activateEvt ; Activate/deactivate event processing
MOVE myEvent.modifiers,D0; App window status changed
BTST #activeFlag,D0 ; Is app window becoming active ?
IF# NE THEN.S ; Yes
Call _TEActivate(textH:L) ; Call TE to highlight selection and
Call _DisableItem(editMenuH:L, #undoCommand); disable UnDo
ELSE#.S ; App window is becoming inactive
Call _TEDeactivate(textH:L); Unhighlight selection and
Call _EnableItem(editMenuH:L, #undoCommand); enable UnDo
ENDIF#
Leave#.S
Case# updatEvt ; Update event processing
Call _BeginUpDate(myEvent.message:L) ; Window needs updating
MOVEA.L thePort,A3 ; We need thePort^.portRect
Call _EraseRect(portRect(A3):A) ; Call QD to erase text area
Call _TEUpdate(portRect(A3):A, textH:L) ; Call TE to update the text
Call _EndUpDate(myEvent.message:L) ; End update
ENDS#
ENDIF#
TST.B doneFlag
UNTIL# NE
Return
END ; of Sample