Easy to Use Help!
Volume Number: | | 5
|
Issue Number: | | 1
|
Column Tag: | | Assembly Lab
|
Related Info: List Manager
Help! An Easy to Use Help Function
By John Holder, Blue Lake, CA, MacTutor Contributing Editor
Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.
Whats this all about?
This article will show you a way of presenting a Help function (hereafter called DoHelp) for any of your programs that is very easy to implement and use. DoHelp must be XREFed (XREF DoHelp) at the beginning of the source file that calls it. To use it I just add a Help... menu in an appropriate place in your application (I put it right below the standard About Application... menu item in the apple menu). Call it by simply doing a BSR DoHelp when the item has been selected by the user.
DoHelp was created with the Macintosh 68000 Development System. First assemble the file DoHelp.Asm, then run the linker on your applications Linker file to Link DoHelp with the rest of your code, and finally run RMaker on your Rmaker file. You can create the needed help resources with ResEdit (or whatever you prefer) and add them to your applications resource file. YourApp.Link & YourApp.R are shown as examples of how you link your applications code with DoHelps code.
The way DoHelp works is to show a list of resource names (a Help topic list created by showing the names of each help resource in numeric order) using the List Manager. This makes adding and editing Help topics very easy, by using ResEdit or compiling the needed resources with RMaker. The user can click on any name to access its contents, which is displayed in a scrollable text window (which temporarily replaces the list of Help topics). When the user is done reading this, he can click on the button or within the text itself to return to the Help topics. From here he can choose to look at another topic or select the Done with Help button to return to the application.
Why?
I wrote DoHelp to put into my latest shareware application called Form It!. I wanted to keep it as generic as possible so I could use it for any other applications that I might create in the future. I made it so the calling application wouldnt need to know anything specific about the help but would just have to call it when the user needs it. It handles everything else.
Whats happening , step by step.
First, all files needed are Included at the beginning and a couple of often used routines for saving and restoring the registers are defined as Macros. A few standard EQUates are also defined along with some values used by the List Manager. The last EQUate is the resource ID# of the DLOG used to display the Help function. Finally the DoHelp routine is XDEFed so the Linker will know what the heck is going on when its being linked to the code that calls it!
Now a dialog box is created, the default button is hilighted, and we jump to the routine to set up the list of named help resources. To accomplish this, we first calculate the useable width of the cells used in the list by checking the size of the User Items rectangle (right-left-scrollbarwidth = widthofcells) of the Help dialog box (item #2 in this DLOG). Then we create a new list with _LNew and set its selflags field to allow only one item to be selected at a time.
The routine to add each named help resource is then called. We count how many resources of this type there are with _CountResources and set list drawing off so it wont show each item as its being added to the list. Starting from the last resource we cycle through all the resources and add their names to the list with _LAddRow & _LSetCell. After the last resource (the resource id#1 since were adding in reverse) has been put in the list, we exit the loop and turn list drawing on and update the list to draw it.
The Dialog filter
After everything is initialized we go into a loop to watch for dialog events. A Dialog Filter is used to handle the List Manager events, all other dialog events are handled by _ModalDialog. The filter is set up to get values off of the stack (passed by _ModalDialog) and create some local variables by using the LINK instruction to set up a stack frame. When a click occurs in the rectangle of the User Item, _LClick is called to handle scrolling or a selection. If a help topic (list item) is clicked on, the rectangle is erased, we change the buttons (item #1) name to an appropriate message (Done Viewing), the cursor is changed to the watch cursor and we jump to the Do_Help_View routine.
A new Text Edit record is made with _TENew and its text size and font is set. The rectangle around the User Item is framed and a scroll bar is created. The selected cells data is retrieved using _LGetCell to get the name of the resource to read in with _GetNamedResource. If the given resource doesnt exist (why it wouldnt I dont know, but it pays to be safe!) we dispose of the TE record and the scroll bar and return to wait for the next event. Otherwise, we copy the data in the help resource into the Text Edit Record and calculate how many lines are in the data. If there are more lines than one screenfull, the scroll bar is set up to match the amount of lines in the data. Next, we jump to the routine to handle text scrolling using another Dialog Filter to handle it.
If the scroll bar is clicked on, we check which part of the scroll has been clicked and handle each part individually. If the Thumb is clicked, its tracked by _TrackControl until released and then we scroll the text according to the difference between the controls old and new values. The text is scrolled a line at a time or a pagefull at a time depending on the part clicked on. The routine Scroll_The_Text figures how many pixels to scroll by multiplying the height of a line of text (found in the teLineHite field of the TE record) by how many lines of text are to be scrolled.
When either the button or the content of the text in the dialog is clicked, the TE record and the scroll bar are disposed of, the list is updated to show it again, we change the buttons name back to what it was and we return to watch for more list events. If the user clicks on another list item, the whole process starts again. Otherwise if the user clicks the button or hits Return, the dialog and the list handle are disposed of and control is returned to the calling application.
Credits
The basis of some of the routines used in DoHelp (such as the dialog filters and scroll handling routines) are from Dan Westons extremely useful books The Complete Book of Macintosh Assembly Language Programming (volumes I and II). These books have proved very helpful to my learning to use the power of the Mac with Assembly language!
The End...
There are many ways that DoHelp could be enhanced. For instance, a search feature or a way to print selected help topics could be added. The source code is well commented, so anything that this article doesnt explain, the comments should be able clear up. Well, thats it, I hope you find this useful enough to use in your own applications!
;------------------------------------------------------------
;FileName: DoHelp.Asm
;(C) 1988 by John Holder
;------------------------------------------------------------
;What it does:
;A generic Help routine:
;Allows user to click in a list of names (these names are
;actually the names of help resources), and show the data
;contained in this resource (ACSII text), in a scrollable
;window. Nothing about the dialog (other than its id#) is
;known, so the dialog can be modified without changing this
;code. To make topics for your help routine, just create
;NAMED resources of type help (lowercase) in your
;application starting at id#1 and making each id# one more
;than the last one. To create the appearance of subtopics
;just add a few spaces to the beginning of the names of
;the appropriate help resources.
;To use this in your application, just make sure you:
;XREF DoHelp
;at the beginning of your source code and you call it by
;doing a:
;BSR DoHelp
;in the appropriate place in your code
Include Traps.D ; Traps
Include ToolEqu.D; ToolBox equates
Include SysEqu.D ; System equates
Include FSEqu.D ; File equates
Include PackMacs.Txt ; PACKage mgr equates
Include QuickEqu.D ; QDraw equates
MACRO SaveRegs =
MOVEM.LA0-A4/D0-D7,-(SP)
|
MACRO RestoreRegs=
MOVEM.L(SP)+,A0-A4/D0-D7
|
true equ $0100
false equ 0
nilequ 0
arraycolumnsequ 1
arrayrows equ 0
celldepth equ 16 ;depth of Cells in List
modify EQU 14 ;State of keys and button
message equ 2 ;Message returned in EventRecord
DialogIDequ 2000 ;res id# of DLOG resource
XDEF DoHelp ;Define function DoHelp for Linker
;------------------------------------------------------------
;<<<< The beginning of the DoHelp routine >>>>
;------------------------------------------------------------
DoHelp
saveregs
CLR.L -(SP) ;space for ptr
move.w #DialogID,-(sp)
CLR.L -(SP) ;wstorage
MOVE.L #-1,-(SP)
_GetNewDialog
MOVE.L (SP),DialogPtr(A5) ;save ptr
_SetPort
;set up stack for my routine
move.l DialogPtr(A5),-(sp)
move #1,-(sp)
bsr HilightDialogButton
;Set up list of all help resources
bsr SetUpHelpList
_InitCursor
Dialog_Loop
pea DialogsFilter;use filter to watch
pea ItemNumber(A5) ;for List mgr events
_ModalDialog
WhatsTheHaps21
;which item was clicked
cmp.w #1,ItemNumber(A5)
beq Quit_Help;click in Done.. but
bra Dialog_Loop;loop until done
Quit_Help
;all done, lets get outta here!
;dispose of the List handle
move.l ListHandle(A5),-(sp)
_LDispose
;kill the dialog
move.l DialogPtr(A5),-(sp)
_DisposDialog
;return to calling application!
restoreregs
rts
;------------------------------------------------------------
;<< Dialog Filter to watch for list selections in User Item >>
;------------------------------------------------------------
DialogsFilter
;this routine expects parameters to be on the stack (handled
;by _ModalDialog)
;PROCEDURE
;DialogsFilter (thedialog:dialogptr;VAR theEvent:EventRecord
; VAR itemhit:integer): boolean
Parambytes SET 12
tItemHit SET 8 ;a ptr to an int!
tEvent SET 12 ;event rec
tDialogSET 16 ;dialog ptr
result SET 20 ;result returned
iPoint SET -4 ;mouse point
itype SET -6 ;item type
iHdl SET -10 ;item hand
iBox SET -18 ;item rect
localbytes SET -18
link A6,#localbytes
saveregs
;get User Item info (rect)
move.l tDialog(A6),-(sp)
move #2,-(sp)
pea iType(A6)
pea iHdl(A6)
pea iBox(A6)
_GetDItem
move.l tevent(A6),A0
move evtnum(A0),D0
cmp #KeyDwnEvt,D0 ;was it a key down?
beq CheckForEnterorReturn ;yep!
move.l tevent(A6),A0
move evtnum(A0),D0
cmp #mButDwnEvt,D0 ;was it a mouse down?
bne LetDialogHandleIt ;if not, let
;_ModalDialog
;handle
;was it a mouse click in the List Box (User Item)?
lea evtMouse(A0),A0
lea iPoint(A6),A1
move.l (A0)+,(A1)+
pea iPoint(A6)
_GlobalToLocal
clr -(sp)
move.l iPoint(A6),-(sp)
pea iBox(A6)
_PtInRect
move (sp)+,D0
beq LetDialogHandleIt ;not in user item
bsr HandleListEvent ;handle list event!
;weve taken care of the event
move.l tItemHit(A6),A0
move #nil,(A0) ;set itemhit to nil
move #true,result(A6) ;stop _ModalDialog
bra FilterExit ;from handling!
LetDialogHandleIt
move #nil,result(A6)
FilterExit
;restore stack to the way it was before
;and return
restoreregs
unlk A6
move.l (sp)+,A0
adda #parambytes,SP
jmp (A0);rts
;------------------------------------------------------------
; <<<< Check for Return or Enter key press >>>>
;------------------------------------------------------------
CheckForEnterorReturn
;if the Enter or Return key was pushed, set the itemhit to #1
;and set result to false so it will be handled by _ModalDialog
move.l tevent(A6),A0
move.l message(A0),D0
cmp.b #$0d,D0 ;return key?
beq SetResult;yep!
cmp.b #$03,D0 ;Enter key?
beq SetResult;yep!
bra LetDialogHandleIt ;neither key
SetResult
move.l tItemHit(A6),A0
move #1,(A0) ;set itemhit to 1
move #true,result(A6) ;let _ModalDialog
;handle it
bra FilterExit
;------------------------------------------------------------
;<<<< Click in List box! >>>>
;------------------------------------------------------------
;handle a click in the list box area
HandleListEvent
;_LClick will handle scrolling & selection of list
;items
pea iPoint(A6)
_GetMouse
clr -(sp)
move.l iPoint(A6),-(sp)
move tEvent+Modify(A6),-(sp)
move.l listhandle(A5),-(sp)
_LClick
move (sp)+,D0
clr.l TheCell(A5) ;start at cell 0,0
;for _LGetSelect
clr -(sp)
move #true,-(sp)
pea TheCell(A5)
move.l listhandle(A5),-(sp)
_LGetSelect
move (sp)+,D0
beq Click_Not_In_Cell ;no cell selected
;unselect the selected cell
move #false,-(sp)
move.l TheCell(A5),-(sp)
move.l listhandle(A5),-(sp)
_LSetSelect
;de-activate the list
move #false,-(sp)
move.l listhandle(A5),-(sp)
_LActivate
bsr Erase_Rect ;clear topic list
bsr Set_To_DoneViewing ;change button name
bsr GetandSetWatch ;show watch cursor
bsr Do_Help_View ;show text from
;help res
;re-activate the list
move #true,-(sp)
move.l listhandle(A5),-(sp)
_LActivate
Click_Not_In_Cell
rts
;------------------------------------------------------------
; <<<< Show the user selected help text >>>>
;------------------------------------------------------------
;open the named resource and view its contents
Do_Help_View
;Use all of rect except enough room for scroll bar
;for text window
bsr Get_Rect_Of_Item
lea DispRect(A5),A2
sub #16,Right(A2)
;create new Text edit record
clr.l -(sp)
pea DispRect(A5)
pea DispRect(A5)
_TENew
move.l (sp)+,TextHand(A5);store handle
;set TE rec. text to 9 point Monaco
move.l TextHand(A5),A1
move.l (A1),A1
move #9,teSize(A1);Text Size!
move.l TextHand(A5),A1
move.l (A1),A1
move #Monaco,teFont(A1);Text Font!
bsr Frame_The_Rect
bsr Get_Rect_Of_Item
;figure rectangle for scroll bar!
lea DispRect(A5),A2
move Right(A2),D2
sub #15,D2 ;scroll bar width
move D2,Left(A2);left = right - 15
add #1,Right(A2) ;right = right + 1
;we de because the
;text rect is 1
;pixel inside the
;User Items rect
pea DispRect(A5) ;expand top & bottom
move #0,-(sp) ;of rect by 1 pixel
move #-1,-(sp)
_InsetRect
;create scroll bar!
clr.l -(sp)
move.l DialogPtr(A5),-(sp)
pea DispRect(A5) ;scrolls rect
move.l #nil,-(sp)
move #true,-(sp);visible
move #0,-(sp) ;init value
move #0,-(sp) ;min value
move #0,-(sp) ;max value(start at 0)
move #16,-(sp);proc id (16=scroll)
clr.l -(sp) ;refCon
_NewControl
move.l (sp)+,ScrollHand(A5) ;save handle
move #255,DataLength(A5) ;max length of
;data allowed
;Get the selected cells data
lea AString(A5),A0 ;pt to byte after
add.l #1,A0 ;length byte
move.l A0,-(sp) ;put ptr on stack
pea DataLength(A5) ;data length var
move.l TheCell(A5),-(sp)
move.l ListHandle(A5),-(sp)
_LGetCell
;add length of data to String ptr
lea ASTring(A5),A0
move DataLength(A5),D0
move.b D0,(A0)
;get the res. & load it
clr.l -(sp)
move.l #help,-(sp)
pea AString(A5)
_GetNamedResource
move.l (sp),ResHand(A5)
_LoadResource
;just to make sure the resource exists!
move.l ResHand(A5),A0
cmp.l #nil,A0 ;does res. exist?
bne A_Ok;yep,its there, go on
bsr DumpStuff;no such resource!
rts ;return
A_Ok
move.l ResHand(A5),A0 ;lock handle
_HLock
;size of handle (text data)
move.l ResHand(A5),A0
_GetHandleSize
move.l D0,D2 ;D2 = length of text data
;set up Text Edit Record to use help data
move.l ResHand(A5),A0 ;need text ptr
move.l (A0),-(sp) ;convert handle
move.l D2,-(sp) ;text length
move.l TextHand(A5),-(sp)
_TESetText
move.l ResHand(A5),A0 ;unlock handle
_HUnLock
;see how many lines of text are in the
;help data
move.l TextHand(A5),A1
move.l (A1),A1
move tenLines(A1),d3 ;D3= lines of text!
;see how many lines fit into rect of user
;item of dialog box
bsr Calc_Lines_In_One_Windowful
move LinesInWind(A5),D1
sub D1,D3 ;sub enough for a
cmp #nil,D3 ;window full!
ble Wont_Pass_Bottom ;not enough lines
;to adda scroll bar
;set the scroll bars max value by the # of lines
move.l ScrollHand(A5),-(sp)
move D3,-(sp) ;# of lines
_SetMaxCtl
Wont_Pass_Bottom
;update the text
pea DispRect(A5)
move.l TextHand(A5),-(sp)
_TEUpDate
_InitCursor
;go watch for text events
bsr HandleTextEditDialogEvent
rts ;done with the text, return
;------------------------------------------------------------
;<<<< Handle events in Dialog box (with text scrolling)! >>>>
;------------------------------------------------------------
HandleTextEditDialogEvent
saveregs
D_Loop
pea CheckTextScroll ;filter to watch
pea ItemNumber(A5) ;for text scrolling
_ModalDialog
;check which buttons are clicked here
cmp.w #1,ItemNumber(A5)
beq Done_With_This ;done viewing text
;if ItemNumber(A5) = 2, that means the user
;clicked in the content of the text of the dialog
;which is handled the same as clicked the
;Done Viewing button
cmp.w #2,ItemNumber(A5)
beq Done_With_This ;done viewing text
bra D_Loop ;keep looping
;------------------------------------------------------------
; <<<< Finished here with text view >>>>
;------------------------------------------------------------
Done_With_This
bsr DumpStuff
restoreregs
rts
;------------------------------------------------------------
; <<<< Dump TE rec. & scroll bar >>>>
;------------------------------------------------------------
DumpStuff
;dispose of text edit record
move.l TextHand(A5),-(sp)
_TEDispose
;dispose of Scroll bar
move.l ScrollHand(A5),-(sp)
_DisposControl
bsr Erase_Rect ;erase the rect
;reset text font & size to System values
move #12,-(sp);12 point
_TextSize
move #0,-(sp) ;Use System Font
_TextFont
;re-show the list by causing list update
MOVE.L DialogPtr(A5),A1
move.l 24(A1),-(sp)
move.l ListHandle(A5),-(sp)
_LUpdate
bsr Frame_The_Rect ;re-frame list rect
bsr Set_To_DoneWithHelp
rts
;------------------------------------------------------------
; <<<< Dialog Filter to watch for text scrolling >>>>
;------------------------------------------------------------
CheckTextScroll
;this routine expects parameters to be on the stack (set up
;by _ModalDialog)
;PROCEDURE
;CheckTextScroll (thedialog:dialogptr;VAR theEvent:EventRecord
; VAR itemhit:integer): boolean
Parambytes SET 12
tItemHit SET 8 ;a ptr to an int!
tEvent SET 12 ;event rec
tDialogSET 16 ;dialog ptr
result SET 20 ;result returned
iPoint SET -4 ;mouse point
itype SET -6 ;item type
iHdl SET -10 ;item hand
iBox SET -18 ;item rect
PartCode SET -20 ;used for scroll
localbytes SET -20
link A6,#localbytes
saveregs
move.l tDialog(A6),-(sp)
move #2,-(sp)
pea iType(A6)
pea iHdl(A6)
pea iBox(A6)
_GetDItem
;only rect in user item will be scroll bar that
;this dialog filter handles
lea iBox(A6),A2
move Right(A2),D2
sub #16,D2 ;scroll bar width
move D2,Left(A2);left = right - 16
move.l tevent(A6),A0
move evtnum(A0),D0
cmp #KeyDwnEvt,D0 ;was it a key down?
beq CheckForEnterorReturn2;yep!
move.l tevent(A6),A0
move evtnum(A0),D0
cmp #mButDwnEvt,D0 ;was it a mouse down?
bne LetDialogHandleIt2 ;if not, let
;_ModalDialog
;handle
;change mouse pt into local coordinates
lea evtMouse(A0),A0
lea iPoint(A6),A1
move.l (A0)+,(A1)+
pea iPoint(A6)
_GlobalToLocal
;was it a mouse click in the Text Box scroll
;bar (User Item)?
clr -(sp)
move.l iPoint(A6),-(sp)
pea iBox(A6)
_PtInRect
move (sp)+,D0
beq LetDialogHandleIt2 ;not in scroll,
;let dialog handle
bsr HandleScroll ;go handle text
;scroll event!
;weve taken care of the event
move.l tItemHit(A6),A0
move #nil,(A0) ;set itemhit to nil
move #true,result(A6) ;set result to true,
bra FilterExit2 ;stop _ModalDialog
;from handling
LetDialogHandleIt2
move #nil,result(A6) ;set to nil, let
;_ModalDialog handle
;it
FilterExit2
;get out of the routine here!
restoreregs
unlk A6
move.l (sp)+,A0
adda #parambytes,SP
jmp (A0);rts
;------------------------------------------------------------
; <<<< Check for Return or Enter key press >>>>
;------------------------------------------------------------
CheckForEnterorReturn2
;if the Enter or Return key was pushed set the itemhit to #1
;and set result to false so it will be handled!
move.l tevent(A6),A0
move.l message(A0),D0
cmp.b #$0d,D0 ;return key?
beq SetResult2 ;yep!
cmp.b #$03,D0 ;Enter key?
beq SetResult2 ;yep!
bra LetDialogHandleIt2;neither key
SetResult2
move.l tItemHit(A6),A0
move #1,(A0) ;set itemhit to 1
move #true,result(A6) ;let modaldialog
bra FilterExit2 ;handle it
;------------------------------------------------------------
;------------------------------------------------------------
; <<<< ALL text scrolling routines >>>>
;------------------------------------------------------------
;------------------------------------------------------------
;------------------------------------------------------------
; <<<< Click in Text Scroll bar >>>>
;------------------------------------------------------------
HandleScroll
pea iPoint(A6)
_GetMouse
clr -(sp)
move.l iPoint(A6),-(sp)
move.l DialogPtr(A5),-(sp)
pea WhichControl(A5)
_FindControl
move (sp)+,PartCode(A6)
beq ScrollDone ;not in any control
;was click in the scroll bar?
;compare value returned by _FindControl & the
;scrolls handle we have stored, if they are
;equal then do the scroll routines
move.l ScrollHand(A5),D0
move.l WhichControl(A5),D1
cmp.l D0,D1
beq Click_In_Scroll
bra ScrollDone ;click not in scroll
Click_In_Scroll
;which part of scroll?
cmp #inUpButton,PartCode(A6)
beq DoUpSCroll
cmp #inDownButton,PartCode(A6)
beq DoDownSCroll
cmp #inPageUp,PartCode(A6)
beq DoPageUpSCroll
cmp #inPageDown,PartCode(A6)
beq DoPageDownSCroll
cmp #inThumb,PartCode(A6)
beq DoThumb
bra ScrollDone
;handle different parts of scroll
DoUpSCroll
clr -(sp)
move.l WhichControl(A5),-(sp)
move.l iPoint(A6),-(sp)
pea UpActionProc
_TrackControl
move (sp)+,D0
bra ScrollDone
DoDownSCroll
clr -(sp)
move.l WhichControl(A5),-(sp)
move.l iPoint(A6),-(sp)
pea DownActionProc
_TrackControl
move (sp)+,D0
bra ScrollDone
DoPageUpSCroll
clr -(sp)
move.l WhichControl(A5),-(sp)
move.l iPoint(A6),-(sp)
pea PageUpActionProc
_TrackControl
move (sp)+,D0
bra ScrollDone
DoPageDownSCroll
clr -(sp)
move.l WhichControl(A5),-(sp)
move.l iPoint(A6),-(sp)
pea PageDownActionProc
_TrackControl
move (sp)+,D0
bra ScrollDone
;handle click in thumb of control
DoThumb
clr -(sp)
move.l WhichControl(A5),-(sp)
_GetCtlValue
move (sp)+,D4 ;D4 = old control value
clr -(sp)
move.l WhichControl(A5),-(sp)
move.l iPoint(A6),-(sp)
clr.l -(sp)
_TrackControl
move (sp)+,D0
clr -(sp)
move.l WhichControl(A5),-(sp)
_GetCtlValue
move (sp)+,D3 ;D3 = new cntl value
sub D3,D4 ;D4-D3=new view value
move D4,D6
bsr Scroll_The_Text ;scroll text selected spot
bra ScrollDone
;return from HandleScroll
ScrollDone
rts
;------------------------------------------------------------
; <<<< Handle Up Scroll arrow >>>>
;------------------------------------------------------------
UpActionProc
;offsets into A6 stack
thecontrol set 10
pcode set 8
parambytes set 6
link A6,#0
saveregs
tst pcode(A6)
beq UpActionDone
clr -(sp)
move.l WhichControl(A5),-(sp)
_GetCtlValue
move (sp)+,D1
beq UpActionDone ;do nothing if control
;value is already 0
sub #1,D1 ;sub 1 from scroll val
move.l WhichControl(A5),-(sp)
move D1,-(sp)
_SetCtlValue ;set to new value
move #1,D6 ;d6 = how many lines
bsr Scroll_The_Text ;to scroll!
UpActionDone
restoreregs
unlk A6
move.l (sp)+,A1
adda.w #parambytes,SP
jmp (a1);rts
;------------------------------------------------------------
; <<<< Handle Down Scroll arrow >>>>
;------------------------------------------------------------
DownActionProc
;offsets into A6 stack
thecontrol set 10
pcode set 8
parambytes set 6
link A6,#0
saveregs
tst pcode(A6)
beq DownActionDone
clr -(sp)
move.l WhichControl(A5),-(sp)
_GetCtlValue
move (sp)+,D2
add #1,D2 ;add 1 to scroll val
clr -(sp)
move.l WhichControl(A5),-(sp)
_GetMaxCtl
move (sp)+,D1
;dont scroll past controls max setting!
cmp D1,D2
bgt DownActionDone
move.l WhichControl(A5),-(sp)
move D2,-(sp)
_SetCtlValue
move #-1,D6 ;d6 = how many lines
bsr Scroll_The_Text ;to scroll!
DownActionDone
restoreregs
unlk A6
move.l (sp)+,A1
adda.w #parambytes,SP
jmp (a1);rts
;------------------------------------------------------------
; <<<< Handle PageUp Scroll arrow >>>>
;------------------------------------------------------------
PageUpActionProc
;offsets into A6 stack
thecontrol set 10
pcode set 8
parambytes set 6
link A6,#0
saveregs
tst pcode(A6)
beq PageUpActionDone
clr -(sp)
move.l WhichControl(A5),-(sp)
_GetCtlValue
move (sp)+,D1
move LinesInWind(A5),D0
sub #1,D0
sub D0,D1
move D0,D6 ;d6 = how many lines
;to scroll!
;are we going to go before 1st line?
;if so, figure how many lines from current position
;until 0 (zero) and use that # to scroll text!
cmp #nil,D1
bge Not_Past_Begin2
add D1,D6 ;set to proper value
;for scroll
move #nil,D1 ;to set ctrl
Not_Past_Begin2
move.l WhichControl(A5),-(sp)
move D1,-(sp)
_SetCtlValue
bsr Scroll_The_Text
PageUpActionDone
restoreregs
unlk A6
move.l (sp)+,A1
adda.w #parambytes,SP
jmp (a1);rts
;------------------------------------------------------------
; <<<< Handle PageDown Scroll arrow >>>>
;------------------------------------------------------------
PageDownActionProc
;offsets into A6 stack
thecontrol set 10
pcode set 8
parambytes set 6
link A6,#0
saveregs
tst pcode(A6)
beq PageDownActionDone
clr -(sp)
move.l WhichControl(A5),-(sp)
_GetCtlValue
move (sp)+,D7
move D7,D2
move LinesInWind(A5),D0
sub #1,D0
add D0,D2
neg D0
move D0,D6 ;d6 = how many lines
;to scroll!
;are we going to go after last line?
;if so, figure how many lines from current position
;until last line and use that # to scroll text
clr -(sp)
move.l WhichControl(A5),-(sp)
_GetMaxCtl
move (sp)+,D3 ;to set ctrl
cmp D3,D2
ble Not_Past_End
sub D3,D7 ;set to proper value
move D7,D6 ;for scroll
move D3,D2 ;to set ctrl
Not_Past_End
move.l WhichControl(A5),-(sp)
move D2,-(sp)
_SetCtlValue
bsr Scroll_The_Text
PageDownActionDone
restoreregs
unlk A6
move.l (sp)+,A1
adda.w #parambytes,SP
jmp (a1);rts
;------------------------------------------------------------
; <<<< Do the actual text scrolling >>>>
;------------------------------------------------------------
Scroll_The_Text
;d6 has how many lines and which direction to scroll
;(depending on whether the value is pos. or neg.)
;use teLineHite to figure how many pixels to scroll
;by multiplying it with the amount of lines
clr.l D2
move.l TextHand(A5),A2
move.l (A2),A2
move teLineHite(A2),D2
muls D6,D2
move #nil,-(sp) ;no horiz. scroll
move D2,-(sp) ;vert. scroll
move.l TextHand(A5),-(sp)
_TESCroll
rts
;<<<< END of all text scrolling routines >>>>
;------------------------------------------------------------
; <<<< How many text lines can fit in user item rect >>>>
;------------------------------------------------------------
Calc_Lines_In_One_Windowful
saveregs
bsr Get_Rect_Of_Item
clr.l D4
lea DispRect(A5),A2
move Top(A2),D3
move Bottom(A2),D4
sub D3,D4 ;Top-Bottom = how many
;pixels in text view box
;D4= heighth (in pixels)
;of help window
clr.l D5
move.l TextHand(A5),A2
move.l (A2),A2
move teLineHite(A2),D5 ;rect heighth
divu D5,D4 ;divided by the
;heighth of one
;line of text =
;how many lines
;can fit!
;D4 now = how many lines of text can fit into one
;screen of the user item of the dialog box!
move D4,LinesInWind(A5)
restoreregs
rts
;------------------------------------------------------------
; <<<< Erase inside of user item rect of dialog >>>>
;------------------------------------------------------------
Erase_Rect
;erase entire user item rectangle
bsr Get_Rect_Of_Item
pea DispRect(A5)
_EraseRect
rts
;------------------------------------------------------------
; <<<< Get user item rect of dialog >>>>
;------------------------------------------------------------
Get_Rect_Of_Item
;Get info from User Item #2
move.l DialogPtr(A5),-(SP)
move #2,-(sp)
pea ItemType(A5)
pea ItemHandle(A5)
pea DispRect(A5)
_GetDItem
rts
;------------------------------------------------------------
;<<<< Change button to say Done Viewing >>>>
;------------------------------------------------------------
Set_To_DoneViewing
bsr Get_Button_Handle
move.l ItemHandle(A5),-(sp)
pea DoneViewing
_SetCTitle
rts
;------------------------------------------------------------
; <<<< Change button to say Done with Help >>>>
;------------------------------------------------------------
Set_To_DoneWithHelp
bsr Get_Button_Handle
move.l ItemHandle(A5),-(sp)
pea DoneString
_SetCTitle
rts
;------------------------------------------------------------
; <<<< Get handle of button in dialog >>>>
;------------------------------------------------------------
Get_Button_Handle
;Get the buttons handle (for changing the buttons
;title)
move.l DialogPtr(A5),-(SP)
move #1,-(sp)
pea ItemType(A5)
pea ItemHandle(A5)
pea DispRect(A5)
_GetDItem
rts
;------------------------------------------------------------
; <<<< Get watch CURSor and display it >>>>
;------------------------------------------------------------
GetandSetWatch
clr.l -(sp)
move #watchcursor,-(sp)
_GetCursor
move.l (sp)+,A0
move.l (A0),-(sp)
_SetCursor
rts
;------------------------------------------------------------
; <<<< Frame the user item rect of dialog >>>>
;------------------------------------------------------------
Frame_The_Rect
;frame the outside of the user items rectangle
bsr Get_Rect_Of_Item
pea DispRect(A5) ;Inset rect by 1
move #-1,-(sp) ;outward
move #-1,-(sp)
_InSetRect
pea DispRect(A5)
_FrameRect
rts
;------------------------------------------------------------
; <<<< Hilight A Dialog Button >>>>
;------------------------------------------------------------
;this routine expects parameters to be on the stack
;PROCEDURE HilightDialogButton (WPtr: Ptr; WhichItem: Int)
;Will hilight a button in a dialog box
HilightDialogButton
WindPt SET 10
WhichItemSET 8
parambytes SET 6
;local variables
TheTypeSET -4 ;Vars for _GetDItem
TheHandleSET -8;handle
TheRectSET -16 ;item rect
localbytes SET -16 ;for link
link A6,#localbytes
saveregs
move.l WindPt(A6),-(SP)
_SetPort
move.l WindPt(A6),-(SP)
move WhichItem(A6),-(sp)
pea TheType(A6)
pea TheHandle(A6)
pea TheRect(A6)
_GetDItem
move #3,-(sp)
move #3,-(sp)
_PenSize
pea TheRect(A6)
move #-4,-(sp)
move #-4,-(sp)
_InSetRect
pea TheRect(A6)
move #16,-(sp)
move #16,-(sp)
_FrameRoundRect
move #1,-(sp)
move #1,-(sp)
_PenSize
restoreregs
unlk A6
move.l (sp)+,A0
adda #parambytes,SP
jmp (A0);rts
;------------------------------------------------------------
; <<<< Set up the dialog box with the help info >>>>
;------------------------------------------------------------
SetUpHelpList
saveregs
bsr Calc_Cell_Width
bsr Get_Rect_Of_Item
;must allow room for the lists scroll bar on the right
;side so subtract 15 from the rects right side!
lea DispRect(A5),A1
sub #15,right(A1)
;set up the arrayrect (for the cells rows and columns)
;for the List Mgr
lea arrayrect(A5),a0
move.l #0,(A0)+
move #arrayRows,(A0)+
move #arraycolumns,(A0)+
move #celldepth,D0
swap D0
move cellWidth(A5),D0
;create a new List
clr.l -(sp)
pea DispRect(A5) ;list rect!
pea arrayrect(A5)
move.l D0,-(sp) ;cell size
move #0,-(sp) ;res id of proc.
move.l DialogPtr(A5),-(sp) ;window ptr
move.w #false,-(sp) ;draw it?
move #false,-(sp) ;has grow?
move #false,-(sp) ;horiz scroll?
move #true,-(sp);vert scroll?
_LNew
move.l (sp)+,ListHandle(A5)
;set selflags to allow only one selection at a time!
move.l ListHandle(A5),A0
move.l (A0),A0
move.b #128,selFlags(A0)
;put all the help names (topics) into the list
bsr AddHelpNamesToList
restoreregs
rts
;------------------------------------------------------------
;<<<< Calculate cell width for list manager >>>>
;------------------------------------------------------------
Calc_Cell_Width
bsr Get_Rect_Of_Item
move DispRect+right(A5),D2
move DispRect+left(A5),D3
sub D3,D2
sub #16,D2 ;allow for scroll
move D2,cellwidth(A5) ;return value
rts
;------------------------------------------------------------
; <<<< Add help resource names to List >>>>
;------------------------------------------------------------
AddHelpNamesToList
;this is a routine to add all help resource names
;to a list
saveregs
clr -(sp)
move.l #help,-(sp)
_CountResources
move (sp)+,D4 ;how many there are
move D4,D7
beq None_Here ;if no help ress
;here, quit!
sub #1,D4 ;sub 1 for looping
;(the DBRA later)
move #false,-(sp) ;set drawing off
move.l ListHandle(A5),-(sp)
_LDoDraw
move.l #nil,TheCell(A5) ;start with zero cell
;set ResLoad off (so resources are not
;automatically read into memory)
move #false,-(sp)
_SetResLoad
AddhelpLoop
clr.l -(sp)
move.l #help,-(sp)
move D7,-(sp) ;res. id #
_GetResource
move.l (sp),A4 ;leave handle on stack
;for next routine
;get the resources name
pea ResId(A5)
pea ResType(A5)
pea ResName(A5)
_GetResInfo
lea ResName(A5),A3
clr.l D3
move.b (A3)+,D3 ;how many chars in
;name for later
sub #1,D7 ;decrement index #
;D7 = the res id#
;d3 = how many characters in string,
;A3 = ptr to string data
;add a new row
clr -(sp)
move #1,-(sp)
move #0,-(sp)
move.l ListHandle(A5),-(sp)
_LAddRow
move (sp)+,D0
;set the cells data to the resources name
move.l A3,-(sp) ;points to name
move D3,-(sp) ;how many chars?
move.l TheCell(A5),-(sp)
move.l ListHandle(A5),-(sp)
_LSetCell
dbra D4,AddhelpLoop ;loop until D4 = 0
;set ResLoad back on
move #true,-(sp)
_SetResLoad
move #true,-(sp);turn drawing on
move.l ListHandle(A5),-(sp)
_LDoDraw
;update the list to show it
MOVE.L DialogPtr(A5),A1
move.l 24(A1),-(sp)
move.l ListHandle(A5),-(sp)
_LUpdate
bsr Frame_The_Rect
None_Here
restoreregs
rts
;------------------------------------------------------------
; <<<< Constants >>>>
;------------------------------------------------------------
DoneStringdc.b 14,Done with Help
.align 2
DoneViewing dc.b 12,Done viewing
.align 2
;------------------------------------------------------------
; <<<< Global variables >>>>
;------------------------------------------------------------
WhichControlds.l 1 ;used by _FindControl
TextHandds.l1 ;TE record Handle
ScrollHandds.l 1 ;Handle of scroll bar
DialogPtr ds.l 1 ;Ptr to Help Dialog
LinesInWind ds 1 ;how many text lines fit in rect
AString ds.b256 ;Space for a string
ListHandleds.l 1 ;Handle to list
TheCell ds.l1 ;Used by the List Mgr
ArrayRect ds.l 2 ;Rows & columns for List Mgr
cellwidth ds.w 1 ;width of cell in list
DataLengthds.w 1 ;Var used by _LGetCell
ItemTypeds.l1 ;Vars used by _GetDItem
ItemHandleds.l 1 ;Handle of Dialog Item
DispRectds.l2 ;Rect of Dialog Item
ResHand ds.l1 ;Handle of a help resource
ResId ds.w1 ;Vars used by _GetResInfo ID#
ResType ds.l1 ;res. type
ResName ds.b256 ;res. name
ItemNumberds.w 1 ;Item# returned by _ModalDialog
END
* File name: YourApp.R
* Example .R file for YourApp, which
* is an example application name
* that has been linked with DoHelp.
* Resource is also an example name, it
* should be the name of a resource file
* containing all of the needed resources for
* YourApp, Including the help resources for
* DoHelp which you can create using ResEdit
* This also creates the DLOG & DITL that
* DoHelp needs.
MDS1:YourApp
APPLTEST
Type DLOG
,2000
Help
56 32 318 476
visible NoGoAway
4
0
2000
Type DITL
,2000
3
Button
232 152 256 288
Done with help
userItem
8 8 200 434
staticText Disabled
208 96 224 344
Click on a Help topic (above) to view.
INCLUDE MDS2:YourApp.Code
INCLUDE MDS1:Resources