MacTech Network:   MacForge.net  |  Computer Memory  |  Register Domains  |  Printer Supplies  |  Cables  |  iPod Deals  |  Mac Deals  |  Mac Book Shelf


  MacTech Magazine

The journal of Macintosh technology

 
 
FileGenius: File Transfer & Management

Magazine In Print
  About MacTech  
  Home Page  
  Subscribe  
  Archives DVD  
  Submit News  
  Submit a Tip!  
  Get a copy of MacTech RISK FREE  
Google
Entire Web
mactech.com
Mac Community
More...
MacTech Central
  by Category  
  by Company  
  by Product  
MacTech News
  MacTech News  
  Previous News  
  MacTech RSS  
Article Archives
  Show Indices  
  by Volume  
  by Author  
  Source Code FTP  
Inside MacTech
  Writer's Kit  
  Editorial Staff  
  Editorial Calendar  
  Back Issues  
  Advertising  
Contact Us
  Customer Service  
  MacTech Store  
  Legal/Disclaimers  
  Webmaster Feedback  
ADVERTISEMENT
Click Here
Volume Number:4
Issue Number:7
Column Tag:Assembly Language Lab

Font Dialog Box Using List Manager

By Ray A. Cameron, Brunswick, Victoria, Australia

Ray. A. Cameron is an Electrical Engineer from Brunswick, Victoria in Australia, employed by Telecom, the Australian Telecommunication Commission. He is currently involved in the introduction of optical fibre into the Customer Access Network. This is his first article for MacTutor.

MacTutor Down Under

Before I start writing about my routines l’d like to say how fantastic MacTutor is for the service that it is providing to Mac programmers in disseminating programming ideas and techniques. It doesn’t matter which language we program in, it is possible to gain information from every article published in MacTutor.

Something that I know would be beneficial to all readers of MacTutor is if the writers of articles include in their description not only how the program works (as published) but what problems they have encountered along the way or techniques thay have employed and why. Also any idiosyncrasies in the system software that don’t appear to be fully explained in Inside Macintosh.

What This Program Does

The FontDialog routine displays a Modal Dialog box for the user to select a font name, size and style. The routine is designed to be incorporated into a program, as I have done with the “Window” example (distributed with the old MDS software and included here), which is on this month’s source disk. There are two routines that I have written, the first routine (SetupFontMap) creates a record of all the ‘FONT’ resources available to the user in the system file. It doesn’t look for ‘FOND’ or ‘NFNT’ resources or fonts attached to documents. The next routine (FontDialog) creates a Modal Dialog box (Fig 1) so that the user can choose a font name, size and style. The font name and size lists are created with the List Manager from data stored in the FontMap record. The routine also includes a UserFilter with the Modal Dialog to handle events.

Some of the procedures and functions used in the FontDialog routine take up a number of lines and are used often so l’ve converted them into Macros to save space. I won’t describe the Macro file as it should be self explanatory.

Fig. 1 Our Font Dialog Box selects text, size & style

User Interface

The Dialog box presented in this example is similar to the one in Microsoft Word. Now that we can all use nested menus to select font, size and style, you might want to be old fashioned and go back to a text dialog box instead! You can select a font name by either clicking on a font name or by typing a character to select the first name starting with that character (or the first name to follow in alphabetical order). As you continue to type additional characters (up to 31) any file that matches the characters you type is found and selected. If you pause while typing, the next character is considered to be a new request, rather than a continuation of your first request. The Delay Until Repeat setting which you set in the (Control Panel) determines how long you can pause before additional characters are considered to be a new request. Hence our dialog box is fairly intelligent in that it includes a sort and search routine and uses the list manager, useful techniques for a variety of dialog functions.

The Font Size Selection Window displays the sizes that are currently available on the system (for the selected font name). If no font name is selected then the Font Size Selection Window is blank, this doesn’t affect the font size in the textedit window. A font size can be selected by clicking on the desired size or by typing in the font size. Numbers and the ‘back space’ character are assumed to be an input to alter the font size, whilst all other characters (except ‘cr’ & ‘enter’) are used to find a matching font name. The font style has been separated into two sections, ‘spacing’ (condense and extend) and ‘style’ (outline, bold, etc). When the dialog box is first displayed the radio buttons and check boxes reflect the current settings. If their settings are altered it is possible to reset them to their original values by clicking on the group title concerned (either ‘spacing’ or ‘style’). The settings are only reset if the mouse is released inside the title. To indicate that the mouse is inside the title the thickness of the frame around the group doubles. This type of facility (interface) lends itself to having the groups set to normal or plain if a double click occurs in the title, something which I haven’t implemented here.

At the bottom of the dialog box is displayed some (sample) text showing the affect of the selected settings. The sample text will only be displayed if the current settings of font name and size are valid. A valid font size can be from 4 to 127, normal quickdraw limitations.

If the Ok button is selected or the ‘cr’ or ‘enter’ keys are pressed while the current settings are invalid an alert box is displayed indicating which setting isn’t valid.

Fig. 2 After text selection, our sample text window allows typing in the chosen font & style

FontMap

To produce the dialog box I require the names of the available fonts on the system as well as the sizes available for each font. The idea of a font menu with a range of font sizes on it (ie MacWrite) is relatively easy, all that is required is to test if the selected font has a desired size. If it does then the size is shown in outlined style, whilst if it doesn’t its style is plain. To find every size available on the system for a particular font name is a little harder. I decided to produce a relocatable block which would contain the names of all the fonts (in alphabetical order) and the sizes of each font (in numerical order). Doing this reduces the amount of time required to set-up the Font Name and Font Size Selection Windows. Note that even some commercial software doesn’t bother to alphabetize font lists! A graphical representation of the FontMap is shown in Fig 3. The first (word) field contains the number of different fonts minus one. Then there are font references, one reference (of three words) for each font. The first field is the font number, the next is the offset to the font name and the last is the offset to the font size list. Both offsets are from the start of the FontMap. The font references are sorted into the alphabetical order of the font names. The space allocated for each font name is the smallest number of even bytes that the name will fit in. The font sizes for each font are sorted into their numerical order within each font size list. The first word of the font size list is the number of font sizes in the list, then follows the font sizes, one word per font size. The handle to the Map is stored for access by the FontDialog routine and could be used to prepare the font sizes in a menu. By having the names and sizes sorted within FontMap it means that when they are placed into a list their cell position relates to their position in the FontMap.

Fig. 3 Layout of our custom font map structure

Apple have laid down in their user interface guidelines that font sizes that exist on a system be represented in some way, as in outlining in a menu etc. With the new font family resources (‘FOND’s & ‘NFNT’s) it is possible to have a font that already has a style attribute associated with it, like Geneva Shadow. How are these fonts to be represented so that the user can tell them apart from a plain font size? The text sample is one solution and perhaps there are others.

Creating the Font Map

The SetupFontMap routine is called at the start of a program so that the FontMap can be used to set up the font size menu items. The routine, first of all evaluates what size to make the Map (relocatable block). It examines each ‘FONT’ resource on the system and determines if the resource contains a font name or a font size. If the resource is a font name, the font (resource) ID and the pointer to the name are stored on the stack. If the resource is a font size, the font (resource) ID is stored in a non-relocatable block (SizeBlock). As each resource is examined, a running total is kept of how large to make the FontMap and how many different fonts there are. The FontMap is created and the number of font names minus one is loaded into the first field. The font ID’s and name pointers are loaded into the font references from the stack. The font references are then sorted into the alphabetical order of the font names. The font names are then loaded into the Map, disposing of their original non-reloctable block in the process and replacing the name pointer with an offset. SetupFontMap then goes through SizeBlock and loads in all the font sizes associated with the first font. The sizes are then sorted into numerical order. SetupFontMap then continues until all fonts have their sizes loaded and sorted. All temporary blocks are disposed of as the routine is finished with them. The FontMap is then unlocked and control returns to the main program.

This routine should be rewritten so that it examines the font resources (‘FOND ‘, ‘FONT’ and ‘NFNT’) and the font resources associated with a document. It should also be recalled each time a new document is accessed in case there is a new font resource associated with it. But that’s a task l’ll leave for you. [Note that Apple discourages the use of fonts within documents now. -Ed]

Font Dialog Mechanics

The FontDialog routine would generally be accessed by the selection of a menu item. The items associated with a dialog are stored in an item list which contains the item type, whether it’s enabled or not and a pointer to the routine that will draw the item, as well as other variables. The order of the items in the list is very important (as I found out). The items are drawn and accessed in the order that they appear in the item list. If items overlap, the item highest in the list (lowest item number) takes precedent. I wanted to set up the ‘spacing’ and ‘style’ groups as shown in Fig 1 so that if I clicked on either the title or a control, the program returned from the ModalDialog trap. At this stage of writing the program I wasn’t using a UserFilter so I had to create routines to draw the bold frame around the Ok button and thin frames around the control groups. The problem arose when I wanted to draw the frame and the group title so that the frame wasn’t drawn through the title (as per Fig 1). If the frame is drawn then the title, the routine that draws the title erases a section of the frame where the title goes. To do this the useritem would have to have a lower item number than the title. The useritem that represented the frame was disabled so I thought that the other items that were enabled wouldn’t be affected by it. Wrong! By placing the useritem higher in the item list than the other items I had made all the lower items except for the top half of the title effectively invisible/disabled. To get around this problem (before I used a UserFilter) I placed the useritem lower in the item list and wrote a subroutine similar to TrackHeading. The routine created a region consisting of the useritem rect minus the group title rect, and made it the clipping region, it then drew a frame around the useritem rect and reset the clipping region. For details on regions and clipping check Chris Derossi’s article on “Quickdraw Does Regions!” (Pascal Procedures) in MacTutor Vol 1 No 3, February 1985. When a User Filter is used, the programmer isn’t confined to accessing the dialog items in their order, which simplifies the drawing of the items.

The FontDialog routine creates a non-relocatable block into which it stores all its variables. This was done so that memory is allocated only when the routine is called. It allows the main program to check to see if there is enough spare memory before the routine is called, or the routine could become a separate code segment that isn’t loaded into memory until it’s needed. The routine takes copies of the font number, size and face (style) that are passed to it so that these can be altered without affecting the original values, in case the user decides to cancel the dialog. The routine only accepts a single font variation (number, size and style), it isn’t suitable for altering multiple font variations.

The spacing radio buttons and style check boxes are set up to display the original settings. I made the condense and extend style variations radio buttons because there is no point in both variations being selected (they cancel one another out).

The Font Name and Size Selection Windows are then created and the available font names and sizes are loaded into their respective list. Each list has its selection flags set so that only one cell is selected at a time and empty cells aren’t selectable. Even though the selection flag was set so that only one cell is selected, I found that I could select more than one cell by using the LSetSelect trap. I wanted to set a cell and I assumed that the List Manager would deselect the currently selected cell. Instead I had to deselect the currently selected cell and then select the desired cell (as shown in DKeyDown). When the mouse is used to select a cell, only one cell is selected, all others are deselected.

Only enough cells are created in each list to contain the font names and sizes. In some cases there are blank lines in the list. Clicking below the cells deselects the current selection, sometimes. For some reason it is possible to click below the cells in one spot and have the selection deselected while not in others. The area in which this occurs is the height of a cell.

A Sample Display Text Edit Record is then setup so that the ‘STR ‘ resource number 264 is displayed in the useritem rect at the bottom of the dialog box. The string is displayed with the current font settings, if they are valid, if they aren’t valid then no text is displayed. The text is centered horizontally within the useritem rect, and also vertically if all the lines are visible.

The handles of the string resources to be used by the alert window are then loaded into the local variable block.

As the user modifies the settings in the dialog box, the routine checks to make sure that they are valid. If they aren’t valid a flag (OkActive) is cleared. I originally set the Ok button to be hilited with #254 (if the selections are invalid) which is supposed to make the control inactive but still indicate if it has been clicked in. When I did this, I found that the Ok button would be grey but it wouldn’t indicate if it was clicked in. If I dragged the mouse an outline of the Ok button would move in the vertical axis. The problem occured when I let the default Modal Dialog routine handle the mouse or when I caught the event in the UserFilter and used the TrackControl trap. For this reason l’ve left the Ok button active when the settings are invalid and display an alert if the Ok button, ‘cr’ or ‘enter’ are selected. Before the alert is displayed the routine determines which variables aren’t valid and sets up the param strings accordingly. I haven’t checked to see if this still occurs since my Mac has been “enhanced”. From a user interface perspective it is good practice to inform the user what the problem is instead of not accepting their input or sounding a beep.

After the items have all been set up the ModalDialog trap is called.

Dialog Filter Proc

The DUserFilter filters all the events that it needs to handle and lets the default routine handle the remainder (by returning false). DUserFilter handles its events and returns true and an item No. if the main program is to do some variable updating or house keeping due to the event (ie a new font name is selected). When the DUserFilter handles an event and a setting hasn’t altered, ie a click on the selected font name, the event is converted to a null event.

DNull checks to see if the mouse is within the textedit rect, if it is it converts the cursor to a handle, otherwise it sets it to the arrow. This section of code could be sped up by storing the textedit item rect in the local variable block instead of using the GetDItem trap every time. When ever a font attribute is altered the sample text is erased and the routine waits until KeyThresh ticks have occured and then redraws the sample with the new attributes. The DNull code checks to see if KeyTresh ticks have passed and if the sample requires updating. If it does then the DUserFilter returns true and item number 21 (a disabled useritem).

DMouseDown handles the mouse down events within the two group titles and the two list windows. All other mouse down events are handled by the default ModalDialog routines. When a mouse down occurs in either of the two group titles the routine (TrackHeading) tracks the mouse to see if it is released in it or not. If it is, ModalDialog returns with the item number, otherwise the event is set to null. When a mouse down occurs in either of the List Manager windows the routines check to see if the selection has altered. If it has ModalDialog returns with the item number, otherwise the event is set to null.

DKeyDown checks for a ‘cr’ or ‘enter’ key and returns item No 1 (Ok button) if it finds one. It then checks to see if a number or ‘back space’ character has been pressed, if one has it deselects the selected cell in the Font Size Selection Window (if one is selected) and returns false for the default ModalDialog routine to handle it. DKeyDown then uses the character to search for a font name (NameSearch), as described in the User Interface section. The List Manager trap LSearch isn’t suitable because it only checks for exact matches and I required the routine to check strings using the IUMagString trap. The FontMap is searched through because it is quicker than using the List Manager routines to check each cells contents. The routine then makes sure the desired cell is selected and visible.

DUpdate updates all the items in the dialog box. The update event removes the need to have an item number for every item that is drawn. A prime example is the bold box around the Ok button, another is the frame around the textedit item. Items don’t have to be drawn in the order in which they appear in the dialog’s item list. This allows the frames to be drawn around the ‘spacing’ and ‘style’ control item groups before the group titles are drawn. The programmer has complete control over what is drawn in the dialog and could in fact draw something that isn’t related to an item in the item list. When lists are drawn they don’t have a frame drawn around them, so l’ve had to include one on each list. After everything has been updated the event is set to a null event (SetoNull) and returned.

DActivate activates the dialog box (the two list windows and the dialog box’s text edit record). I’ve also included the code to deactivate the dialog box, even though it never gets used. When the ShowWindow trap is called to display the dialog box the window is created, a deactivate event is created for the original front window as is an activate event for the dialog window. The main program’s deactivate code isn’t accessed because its event loop has been broken, the main program has to deactivate the front window before the dialog box routine is called. DActivate has to be able to filter out the (de)activate event for the original front window and not handle it. When the alert is shown, the dialog should be deactivated (just like the case above) with similar code to that in DDeactivate. The LActivate trap removes (hides) scroll bars when the list is deactivated instead of inactivating them so I didn’t include the deactivate code because it was visually undesirable (sloppy).

The routines that handle the result of the ModalDialog trap perform the following functions:

DOk displays an alert if the settings aren’t valid and returns to the ModalDialog loop (WaitOk). If the settings are valid the original values are replaced with the desired values. The routine then passes onto DCancel.

DCancel closes the dialog box and disposes of the unwanted records and the local variable block. When there is a lot of information to be included (displayed) in a dialog, it is best to initially set the dialog to be invisible, setup the items involved and then show the dialog. This creates a clean crisp presentation, as opposed to items appearing slowly with delays between items. The same philosophy applies when the dialog is being closed. It is better to hide the dialog first and then to dispose of the items rather than to see items within the dialog (window) disappear before the window does, very sloppy.

Style resets the control check boxes to their original settings after the user has clicked in the style title. SStyle toggles a check box after it has been clicked in.

Spacing resets the control radio buttons to their original settings after the user clicked in the spacing title. SSpacing sets the radio button that was clicked in and clears the other radio buttons within the group.

The ModalDialog default routine handles a mouse down event in the control items (radio buttons and check boxes) and tracks the mouse and returns (with that items number) if the mouse is released within the item. The main routine then alters the value of the control, knowing that it was clicked in, this allows groups of radio buttons to be organised together.

FontName updates the font number variable after a new font name was selected. The Font Size Selection Window is then updated to show the sizes associated with the new font name. If no font name is selected the Font Size Selection Window is cleared.

FontSize updates the font size variable after a new font size was selected from the Font Size Selection Window. The textedit item (No 20) is then updated to display the new font size. If no font size was selected the textedit item retains its previous value (it isn’t set to zero).

GetEditSize updates the font size variable after the user has altered the textedit item through a key stroke (0 through to 9 or ‘backspace’). The currently selected size in the Font Size Selection Window is deselected. The ModalDialog default routine returns with the textedit item number when the mouse is clicked within its rect even though its value doesn’t change.

FontSample updates the font attributes associated with the sample text at the bottom of the dialog box. The text is then centered vertically within the user item rect if the height of the text lines is less than the height of the rect. The sample is then displayed with the new attributes.

Each of the above routines have code included in them to check if their font variable has in fact altered, if it has the sample text is then erased and isn’t updated until KeyThresh ticks have lapsed.

I’ll leave the remaining description of the routines to the comments placed within each listing. Best of luck with writing your dialog.

Fig. 4 A simple About Box Dialog


Continued in next frame
Volume Number:4
Issue Number:7
Column Tag:Assembly Language Lab

Font Dialog Box Using List Manager (code)


; File Window.Asm
;----------------------------------------------------------
;       Macintosh 68000 Development System
;----------------------------------------------------------
; The Window Sample Program issued with the MDS.
; Modified by Ray.A.Cameron to demonstate a Modal Dialog Box.
; Mon May 4, 1988 21:29:54

This application displays a window within which you can enter and edit text. Program control is through four menus: the Apple menu, the File menu, the Edit menu, and the Font menu.The Apple menu has the standard desk accessories and an About feature. The File menu lets you quit the application. The Edit menu lets you cut, copy, paste, and clear the text in the window or in the desk accessories. Undo is provided for desk accesories only. Command key equivalents for undo, cut, copy, and paste are provided. The Font menu lets you display a Modal Dialog Box to select a Font Name, Size and attributes.

;----------------------- Includes ----------------

Include Traps.D  ; Use System and ToolBox traps
Include ToolEqu.D; Use ToolBox equates
Include QuickEqu.D ; Use QuickDraw equates
Include SysEqu.D ; Use System equates
Include PackMacs.Txt ; Use Package equates

;------------------- Use of Registers -----------

; Operating Sys and Toolbox calls preserve D3-D7, A2-A4.

; Register use: A5-A7 are reserved by the system
;  D1-D3, A0-A1 are unused
;  D0 is used as a temp

ModifyReg Equ    D4  ; modifier bits from GetNextEvent 
MenuReg Equ D5   ; menu ID from MenuSelect,MenuKey
MenuItemReg Equ  D6; item ID from MenuSelect,MenuKey
AppleHReg Equ    D7; handle to the Apple Menu

TextHRegEqu A2   ; handle to TextEdit record
WindowPRegEqu    A3; pointer to editing window
EditHRegEqu A4   ; handle to Edit menu

;------------------- Equates ----------------

; These are equates associated with the resources
; for the Window example.

AppleMenu Equ    1 ; First item in MENU resource
  AboutItem Equ  1 ; First item in Apple menu

FileMenuEqu 2  ; Second item in MENU resource
  QuitItem  Equ  1 ; First item in File menu

EditMenuEqu 3  ; Third item in MENU resource
  UndoItemEqu    1 ; Items in Edit menu
  CutItem Equ    3 ; (Item 2 is a line)
  CopyItemEqu    4
  PasteItem Equ  5
  ClearItem Equ  6
  
FontMenuEqu 4  ; Fourth item in MENU resource
  DialogItemEqu  1 ; Only item in Font menu

AboutDialog Equ  1 ; About dialog is DLOG resource #1
ButtonItemEqu    1 ; First item in DITL used by DLOG #1
ASample Equ 1  ; Sample Window is WIND resource #1

;-------------------- Xdefs ----------------

; Xdef all labels to be symbolically displayed by debugger.

 Xdef   Start
 Xdef   InitManagers
 Xdef   SetupMenu
 Xdef   SetupWindow
 Xdef   SetupTextEdit
 Xdef   Activate
 Xdef   Deactivate
 Xdef   Update
 Xdef   KeyDown
 Xdef   MouseDown
 Xdef   SystemEvent
 Xdef   Content
 Xdef   Drag
 Xdef   InMenu
 Xdef   About
 
 XRef   SetupFontMap ; Routines
 XRef   FontDialog
 
 XRef   FontMap  ; Variable
 
;----------------- Main Program -------------
Start 
 Bsr    InitManagers ; Initialize managers
 Bsr    SetupMenu; Build menus, draw menu bar
 Bsr    SetupWindow; Draw Editing Window
 Bsr    SetupTextEdit; Initialize TextEdit
 Bsr    SetupFontMap ; Initialize the FontMap
EventLoop ; Main Program Loop
 _SystemTask; Update Desk Accessories
 ; ProcedureTEIdle (hTE:TEHandle);
 Move.l TextHReg,-(SP)    ; Get handle to text record
 _TEIdle; blink cursor etc.
 
 ; Function GetNextEvent(eventMask: Integer
 ; Var theEvent: EventRecord) : Boolean
 Clr    -(SP)    ; Clear space for result
 Move   #$0FFF,-(SP) ; Allow 12 low events
 Pea    EventRecord; Place to return results
 _GetNextEvent   ; Look for an event
 Move   (SP)+,D0 ; Get result code
 Beq    EventLoop; No event... Keep waiting
 Bsr    HandleEvent; Go handle event
 Beq    EventLoop; Not Quit, keep going
 Rts    ; Quit, exit to Finder

Note: When an event handler finishes, it returns the Z flag set. If Quit was selected, it returns with the Z flag clear. An Rts is guaranteed to close all files and launch the Finder.

;------------------- InitManagers -------------

InitManagers
 Pea    -4(A5)   ; Quickdraw's global area
 _InitGraf; Init Quickdraw
 _InitFonts ; Init Font Manager
 Move.l #$0000FFFF,D0; Flush all events
 _FlushEvents
 _InitWindows    ; Init Window Manager
 _InitMenus ; Init Menu Manager
 Clr.l  -(SP)    ; No restart Procedure
 _InitDialogs    ; Init Dialog Manager
 _TEInit; Init Text Edit
 _InitCursor; Turn on arrow cursor
 Rts

;--------------------- SetupMenu ---------------

SetupMenu

; Apple Menu Set Up.  

 ; Function GetMenu (menu ID:Integer): MenuHandle;
 Clr.l  -(SP)    ; Space for menu handle
 Move   #AppleMenu,-(SP)  ; Apple menu resource ID 
 _GetRMenu; Get menu handle 
 Move.l (SP),AppleHReg  ; Save for later comparison
 Move.l (SP),-(SP) ; Copy handle for AddResMenu
 
 Clr    -(SP)    ; Append to menu
 _InsertMenu; Which is currently empty

 Move.l #'DRVR',-(SP); Load all drivers 
 _AddResMenu; And Add to Apple menu

; File Menu Set Up

 Clr.l  -(SP)    ; Space for menu handle
 Move   #FileMenu,-(SP) ; File Menu Resource ID 
 _GetRMenu; Get File menu handle

 Clr    -(SP)    ; Append to list
 _InsertMenu; After Apple menu

; Edit Menu Set Up

 Clr.l  -(SP)    ; Space for menu handle
 Move   #EditMenu,-(SP) ; Edit menu resource ID
 _GetRMenu; Get handle to menu
 Move.l (SP),EditHReg; Save for later
        ; Leave on stack for Insert
 
 Clr    -(SP)    ; Append to list
 _InsertMenu; After File menu
 
; Font Menu Set Up

 Clr.l  -(SP)    ; Space for menu handle
 Move   #FontMenu,-(SP) ; Font Menu Resource ID 
 _GetRMenu; Get File menu handle

 Clr    -(SP)    ; Append to list
 _InsertMenu; After Edit menu

 _DrawMenuBar    ; Display the menu bar
 Rts

;---------------- SetupWindow ---------------

SetupWindow

 ; Function GetNewWindow (windowID: Integer; wStorage: Ptr; 
 ;       behind: WindowPtr) : WindowPtr;
 Clr.l  -(SP)    ; Space for window pointer
 Move   #ASample,-(SP)    ; Resource ID for window
 Pea    WindowStorage(A5) ; Storage for window
 Move.l #-1,-(SP); Make it the top window
 _GetNewWindow   ; Draw the window
 Move.l (SP),WindowPReg   ; Save for later 
 
 _SetPort ; Make it the current port
 Rts
 
;------------- SetupTextEdit ----------------

SetupTextEdit

 ; ProcedureTENew (destRect,viewRect: Rect): TEHandle;
 Clr.l  -(SP)    ; Space for text handle 
 Pea    DestRect ; DestRect Rectangle
 Pea    ViewRect ; ViewRect Rectangle
 _TENew ; New Text Record
 Move.l (SP)+,TextHReg  ; Save text handle
 Rts
 
;------------- Event Handling Routines --------

HandleEvent

Use the event number as an index into the Event table. These 12 events are all the things that could spontaneously happen while the program is in the main loop.

Move Modify,ModifyReg ; More useful in a reg

Move What,D0 ; Get event number

Add D0,D0 ; *2 for table index

Move EventTable(D0),D0 ; Point to routine offset

Jmp EventTable(D0) ; and jump to it

EventTable

Dc.w NextEvent-EventTable ; Null Event (Not used)

Dc.w MouseDown-EventTable ; Mouse Down

Dc.w NextEvent-EventTable ; Mouse Up (Not used)

Dc.w KeyDown-EventTable ; Key Down

Dc.w NextEvent-EventTable ; Key Up (Not used)

Dc.w KeyDown-EventTable ; Auto Key

Dc.w Update-EventTable ; Update

Dc.w NextEvent-EventTable ; Disk (Not used)

Dc.w Activate-EventTable ; Activate

Dc.w NextEvent-EventTable ; Abort (Not used)

Dc.w NextEvent-EventTable ; Network (Not used)

Dc.w NextEvent-EventTable ; I/O Driver (Not used)

;-------------------- Event Actions -----------------

Activate

An activate event is posted by the system when a window needs to be activated or deactivated. The information that indicates which window needs to be updated was returned by the NextEvent call.

 Cmp.l  Message,WindowPReg; Was it our window?
 Bne  NextEvent  ; No, get next event
 Btst #activeFlag,ModifyReg ; Activate?
 Beq  Deactivate ; No, go do Deactivate

To activate our window, activate TextEdit, and disable Undo since we don't support it. Then set our window as the port since an accessory may have changed it. This activate event was generated by SelectWindow as a result of a click in the content region of our window. If the window had scroll bars, we would do ShowControl and HideControl here too.

 ; ProcedureTEActivate (hTE: TEHandle);
 Move.l TextHReg,-(SP)    ; Move Text Handle To Stack
 _TEActivate; Activate Text

 ; Procedure DisableItem (menu:MenuHandle; item:Integer);
 Move.l EditHReg,-(SP)    ; Get handle to the menu
 Move   #UndoItem,-(SP)   ; Enable 1st item (undo)
 _DisableItem

SetOurPort; used by InAppleMenu

 Move.l WindowPReg,-(SP)  ; an accessory might have
 _SetPort ; changed it.

NextEvent 
 Moveq #0,D0; Say that it's not Quit
 Rts    ; return to EventLoop
 
Deactivate

 Move.l TextHReg,-(SP)    ; Get Text Handle
 _TeDeActivate   ; Un Activate Text
 Move.l EditHReg,-(SP)    ; Get handle to the menu
 Move   #UndoItem,-(SP)   ; Enable 1st item (undo)
 _EnableItem
 Bra    NextEvent; Go get next event
 
Update  

The window needs to be redrawn. Erase the window and then call TextEdit to redraw it.

 ; ProcedureBeginUpdate (theWindow: WindowPtr);
 Move.l WindowPReg,-(SP)  ; Get pointer to window
 _BeginUpDate    ; Begin the update

 ; EraseRect (rUpdate: Rect);
 Pea    ViewRect ; Erase visible area
 _EraseRect
 
 ; TEUpdate (rUpdate: Rect; hTE: TEHandle);
 Pea    ViewRect ; Get visible area
 Move.l TextHReg,-(SP)    ; and handle to text 
 _TEUpdate; then update the window

 ; ProcedureEndUpdate (theWindow: WindowPtr);
 Move.l WindowPReg,-(SP)  ; Get pointer to window
 _EndUpdate ; and end the update
 Bra    NextEvent; Go get next event
 
KeyDown 

A key was pressed. First check to see if it was a command key. If so, go do it. Otherwise pass the key to TextEdit.

 Btst   #CmdKey,ModifyReg ; Is command key down?
 Bne    CommandDown; handle command key

 ; ProcedureTEKey (key: CHAR; hTE: TEHandle);
 Move   Message+2,-(SP)   ; Get character
 Move.l TextHReg,-(SP)    ; and text record
 _TEKey ; Give char to TextEdit
 Bra    NextEvent; Go get next event
 
CommandDown 

The command key was down. Call MenuKey to find out if it was the command key equivalent for a menu command, pass the menu and item numbers to Choices.

 ; Function MenuKey (ch:CHAR): LongInt;
 Clr.l  -(SP)    ; Space for Menu and Item
 Move   Message+2,-(SP)   ; Get character
 _MenuKey ; See if it's a command
 Move   (SP)+,MenuReg; Save Menu
 Move   (SP)+,MenuItemReg ; and Menu Item
 Bra    Choices  ; Go dispatch command


;---------Mouse Down Events And Their Actions-----

MouseDown 

If the mouse button was pressed, we must determine where the click occurred before we can do anything. Call FindWindow to determine where the click was; dispatch the event according to the result.

 ; Function FindWindow (thePt: Point; 
 ;             Var whichWindow: WindowPtr): Integer;
 Clr    -(SP)    ; Space for result
 Move.l Point,-(SP); Get mouse coordinates
 Pea    WWindow  ; Event Window
 _FindWindow; Who's got the click? 
 Move   (SP)+,D0 ; Get region number
 Add    D0,D0    ; *2 for index into table
 Move   WindowTable(D0),D0; Point to routine offset
 Jmp    WindowTable(D0)   ; Jump to routine
 
WindowTable

 Dc.w   NextEvent-WindowTable ; In Desk (Not used)
 Dc.w   InMenu-WindowTable; In Menu Bar
 Dc.w   SystemEvent-WindowTable ; System Window
 Dc.w   Content-WindowTable ; In Content
 Dc.w   Drag-WindowTable  ; In Drag
 Dc.w   NextEvent-WindowTable ; In Grow (Not used)
 Dc.w   NextEvent-WindowTable ; In Go Away (Not used)

SystemEvent 

The mouse button was pressed in a system window. SystemClick calls the appropriate desk accessory to handle the event.

 ; ProcedureSystemClick (theEvent: EventRecord;
 ;              theWindow: WindowPtr);
 Pea    EventRecord; Get event record
 Move.l WWindow,-(SP); and window pointer
 _SystemClick    ; Let the system do it
 Bra    NextEvent; Go get next event
 
Content 

The click was in the content area of a window. If our window was in front, then call Quickdraw to get local coordinates, then pass the coordinates to TextEdit. We also determine whether the shift key was pressed so TextEdit can do shift-clicking. If our window wasn't in front, Move it to the front, but don't process click.

 Clr.l  -(SP)    ; clear room for result
 _FrontWindow    ; get FrontWindow
 Move.l (SP)+,D0 ; Is front window pointer
 Cmp.l  WindowPReg,D0; same as our pointer?
 Beq.s  @1; Yes, call TextEdit

 We weren't active, select our window.  This causes an activate event.

 ; ProcedureSelectWindow (theWindow: WindowPtr);
 Move.l WWindow,-(SP); Window Pointer To Stack
 _SelectWindow   ; Select Window
 Bra    NextEvent; and get next event

@1 

; We were active, pass the click (with shift) to TextEdit.

 ; ProcedureGlobalToLocal (Var pt:Point);
 Pea    Point    ; Mouse Point
 _GlobalToLocal  ; Global To Local

 ; Procedure   TEClick (pt: Point; extend: Boolean; hTE: TEHandle);
 Move.l Point,-(SP); Mouse Point (GTL)
 Btst   #shiftKey,ModifyReg ; Is shift key down?
 Sne    D0; True if shift down

Note: We want the Boolean in the high byte, so use Move.b. The 68000 pushes an extra, unused byte on the stack for us.

 Move.b D0,-(SP) 
 Move.l TextHReg,-(SP)  ; Identify Text
 _TEClick ; TEClick
 Bra    NextEvent; Go get next event
 
Drag

 Move.l WWindow,-(SP); Pass window pointer
 Move.l Point,-(SP); mouse coordinates
 Pea    WBounds  ; and boundaries
 _DragWindow; Drag Window
 Bra    NextEvent; Go get next event
 
InMenu  

 Clr.l  -(SP)    ; Get Space For Menu Choice
 Move.l Point,-(SP); Mouse At Time Of Event
 _MenuSelect; Menu Select
 Move   (SP)+,MenuReg; Save Menu
 Move   (SP)+,MenuItemReg ; and Menu Item

On entry to Choices, the resource ID of the Menu is saved in the low word of a register, and the resource ID of the MenuItem in another. The routine MenuKey, used when a command key is pressed, returns the sameinfo.

Choices ; Called by command key too

 Cmp  #AppleMenu,MenuReg  ; Is It In Apple Menu?
 Beq  InAppleMenu; Go do Apple Menu
 Cmp  #FileMenu,MenuReg ; Is It In File Menu?
 Beq  InFileMenu ; Go do File Menu
 Cmp  #EditMenu,MenuReg ; Is It In Edit Menu?
 Beq  InEditMenu ; Go do Edit Menu
 Cmp  #FontMenu,MenuReg ; Is It In Font Menu?
 Beq  InFontMenu ; Go do Font Menu
 
ChoiceReturn

 Bsr    UnHiliteMenu ; Unhighlight the menu bar
 Bra    NextEvent; Go get next event
 
InFileMenu

 Cmp    #QuitItem,MenuItemReg ; Is It Quit?
 Bne    ChoiceReturn ; No, Go get next event
 Bsr    UnHiliteMenu ; Unhighlight the menu bar
 Move   #-1,D0   ; say it was Quit
 Rts
 
InEditMenu

; First, call SystemEdit.  If a desk accessory is active that uses the 
Edit menu (such as the Notepad) this lets it use our menu. Decide whether 
it was cut, copy, paste, or clear.  Ignore Undo since we didn't implement 
it.

 Bsr    SystemEdit ; Desk accessory active?
 Bne  ChoiceReturn ; Yes, SystemEdit handled it
 Cmp    #CutItem,MenuItemReg; Is It Cut?
 Beq    Cut ; Yes, go handle it
 Cmp    #CopyItem,MenuItemReg ; Is it Copy?
 Beq    Copy; Yes, go handle it
 Cmp    #PasteItem,MenuItemReg; Is it Paste?
 Beq    Paste    ; Yes, go handle it
 Cmp    #ClearItem,MenuItemReg; Is it Clear?
 Beq    ClearIt  ; Yes, go handle it
 Bra    ChoiceReturn ; Go get next event
 
InFontMenu

 Cmp    #DialogItem,MenuItemReg  ; Is It Dialog?
 Bne    ChoiceReturn ; No, Go get next event
 
 ; ProcedureTEDeActivate (hTE: TEHandle)
 Move.l TextHReg,-(SP)    ; Identify Text
 _TEDeActivate   ; Deactivate Text
 
; Obtain the current Font number, size and attributes to setup the dialog 
box.
 Movea.lTextHReg,A0; Handle to the TE record
 Movea.l(A0),A0  ; Pointer to the TE record
 Move.w teFont(A0),D0;- Font Number
 Cmp.w  #1,D0    ;  Default number?
 Bne.s  @0;  No, -> @0
 Move.w ApFontID,D0;  Yes, load default number
@0 Move.w D0,DtxFont(A5)
 Clr.w  D0;- Font Face
 Move.b teFace(A0),D0;   Place the attribute bits in the
 Move.w D0,DtxFace(A5)  ;  low byte of DtxFace(A5).
 Move.w teSize(A0),D0;- Font Size
 Bne.s  @1;  Default size, No -> @1
 Move.b FMDefaultSize,D0  ; Yes, load default size
@1 Move.w D0,DtxSize(A5)
 
 Clr.w  -(SP)
 Pea    DtxFont(A5); Load the font's number address
 Pea    DtxFace(A5); Load the font's face address
 Pea    DtxSize(A5); Load the font's size address
 Jsr    FontDialog

Test to see if the okButton was pressed (ie install the new Font variables). If the cancelButton was pressed leave the Font variables as they are.

 Move.b (SP)+,D0
 Beq.s  @2

Update the Font number, size, and face fields in the textedit record. The teAscent and teLineHite fields also require up dating. Reset the port to the textedit window, since the current GraphPort has been changed by the FontDialog routine.

 Move.l WindowPReg,-(SP)  
 _SetPort
 Move.w DtxFont(A5),-(SP)
 _TextFont
 Move.w DtxFace(A5),-(SP)
 _TextFace
 Move.w DtxSize(A5),-(SP)
 _TextSize
 
 ; Procedure GetFontInfo (Var Info: FontInfo)
 Pea    Info(A5)
 _GetFontInfo
 
 Movea.lTextHReg,A1; DeReference the Handle
 Movea.l(A1),A1
 Move.w DtxFont(A5),teFont(A1); teFont
 Move.b DtxFace+1(A5),teFace(A1) ; teFace
 Move.w DtxSize(A5),teSize(A1); teSize
 Move.w Info+ascent(A5),teAscent(A1) ; teAscent
 Move.w Info+ascent(A5),D0; teLineHite
 Add.w  Info+descent(A5),D0
 Add.w  Info+leading(A5),D0
 Move.w D0,teLineHite(A1)
 
@2 Bra  GoSetOurPort 

InAppleMenu

 Cmp    #AboutItem,MenuItemReg; Is It About?
 Beq  About ; If So Goto About...
 
 ; ProcedureGetItem (menu: MenuHandle; item: Integer; 
 ;                        Var itemString: Str255);
 Move.l AppleHReg,-(SP)   ; Look in Apple Menu
 Move   MenuItemReg,-(SP) ; What Item Number?
 Pea    DeskName ; Get Item Name
 _GetItem ; Get Item

 ; Function OpenDeskAcc (theAcc: Str255) : Integer;
 Clr    -(SP)    ; Space For Opening Result
 Pea    DeskName ; Open Desk Acc
 _OpenDeskAcc    ; Open It
 Move   (SP)+,D0 ; Pop result
 
GoSetOurPort

 Bsr    SetOurPort ; Set port to us 
 Bra    ChoiceReturn ; Unhilite menu and return
 
;----------- Text Editing Routines ---------

Cut; CUT
 Move.l TextHReg,-(SP)    ; Identify Text
 _TECut ; Cut it and copy it
 Bra    ChoiceReturn ; Go get next event
Copy    ; COPY
 Move.l TextHReg,-(SP)    ; Identify Text
 _TECopy; Copy text to clipboard
 Bra    ChoiceReturn ; Go get next event
Paste   ; PASTE
 Move.l TextHReg,-(SP)    ; Identify Text
 _TEPaste ; Paste
 Bra    ChoiceReturn ; Go get next event
ClearIt ;CLEAR
 Move.l TextHReg,-(SP)    ; Point to text
 _TEDelete; Clear without copying
 Bra    ChoiceReturn ; Go get next event

SystemEdit does undo, cut, copy, paste, and clear for desk accessories. It returns False (Beq) if the active window doesn't belong to a desk accessory.

SystemEdit
 
 ; Function SystemEdit (editCmd:Integer): Boolean;
 Clr    -(SP)    ; Space for result
 Move   MenuItemReg,-(SP) ; Get item in Edit menu
 Subq   #1,(SP)  ; SystemEdit is off by 1
 _SysEdit ; Do It 
 Move.b (SP)+,D0 ; Pop result
 Rts    ; Beq if NOT handled

UnhiliteMenu
 
 ; ProcedureHiLiteMenu (menuID: Integer);
 Clr    -(SP)    ; All Menus
 _HiLiteMenu; UnHilite Them All
 Rts
 

;--------------------Misc Routines------------

About



 ; Function GetNewDialog (dialogID: Integer; dStorage: Ptr; 
 ;                             behind: WindowPtr) : DialogPtr
 Clr.l  -(SP)    ; Space For dialog pointer
 Move   #AboutDialog,-(SP); Identify dialog rsrc #
 Pea    DStorage ; Storage area
 Move.l #-1,-(SP); Dialog goes on top
 _GetNewDialog   ; Display dialog box
 Move.l (SP),-(SP) ; Copy handle for Close
 ; Handle on stack
 _SetPort ; Make dialog box the port
 Move.l TextHReg,-(SP)  ; Identify Text
 _TEDeActivate   ; Deactivate Text

WaitOK

 ; ProcedureModalDialog (filterProc: ProcPtr; 
 ;      Var itemHit: Integer);
 Clr.l  -(SP)    ; Clear space For handle
 Pea    ItemHit  ; Storage for item hit
 _ModalDialog    ; Wait for a response

 Move   ItemHit,D0 ; Look to see what was hit
 Cmp    #ButtonItem,D0  ; was it OK?
 Bne    WaitOK   ; No, wait for OK
 
 _CloseDialog    ; Handle already on stack
  Bra   GoSetOurPort ; Set port to us and return
  
; ----------- Data Starts Here ------------

EventRecord ; NextEvent's Record
 What:  Dc  0    ; Event number
 Message: Dc.l   0 ; Additional information
 When:  Dc.l0    ; Time event was posted 
 Point: Dc.l0    ; Mouse coordinates
 Modify:Dc  0    ; State of keys and button
 WWindow: Dc.l   0 ; Find Window's Result

DStorageDcb.w    DWindLen,0 ; Storage For Dialog
DeskNameDcb.w    16,0; Desk Accessory's Name
WBounds Dc  28,4,308,508  ; Drag Window's Bounds
ViewRectDc  5,4,245,405 ; Text Record's View Rect
DestRectDc  5,4,245,405 ; Text Record's Dest Rect
ItemHit Dc0 ; Item clicked in dialog

;-------------- Nonrelocatable Storage ---------

Variables declared using Ds are placed in a global space relative to A5. When these variables are referenced, A5 must be explicitly mentioned.

DtxFont Ds.w1
DtxFace Ds.w1
DtxSize Ds.w1
Info    Ds.w4    ; FontInfo Record
WindowStorage    Ds.wWindowSize  ; Storage for Window

End

;-------------- FontDialog --------------------

; Written by Ray.A.Cameron
; Version 1
;Wed May 6, 1988 21:00:51


XDef    FontDialog ; Routine's name
XRef    FontMap  ; Variable's name

;---------- Includes -------------

Include Traps.D  ; Use System and ToolBox traps
Include ToolEqu.D; Use ToolBox Equates
Include QuickEqu.D ; Use QuickDraw Equates
Include SysEqu.D ; Use System Equates
Include PackMacs.Txt ; Use Package Equates
Include FontMacros.Txt  ; Use Macro file


; ---------- Equates ----------
FontDPtrEqu A4

FDialog Equ 260  ; Font dialog is DLOG resource #260
ADialog Equ 260  ; Alert dialog is ALRT resource #260
True    Equ 1    ; Boolean True
False   Equ 0    ; Boolean False
enterCode Equ  3 ; ASCII Enter
bsCode  Equ 8    ; ASCII Back Space
crCode  Equ 13   ; ASCII Carriage Return
param0  Equ 0    ; Offset to string 0 in DAStrings
param1  Equ 4    ; Offset to string 1 in DAStrings
param2  Equ 8    ; Offset to string 2 in DAStrings
OkActiveEqu 0    ; OkActive bit within Dialog Flags
SUpdate Equ 1    ; Sample update bit within Dialog Flags


Font Dialog 2






























   
   















  MacTech Network:   MacForge.net  |  Computer Memory  |  Register Domains  |  Printer Supplies  |  Cables  |  iPod Deals  |  Mac Deals  |  Mac Book Shelf


  MacTech Magazine

The journal of Macintosh technology

 
 
StuffIt