21 KiB
MouseGraphics ToolKit
This is a complex API library written by Apple circa 1985. It consists of:
- Graphics Primitives - screen management, lines, rects, polys, text, patterns, pens
- Mouse Graphics - windows, menus, events, cursors
For the purposes of DeskTop, the entry point is fixed at $4000 AUX, called MLI-style:
JSR $4000
.byte call
.addr params
Result will be in A, with Z bit set, 0 indicating success (so BNE error
works).
ca65 syntax is used for primitives: .byte
, .word
(interpreted as 16-bit signed integer), .addr
(16-bit address), .res N
(N byte buffer)
Graphics Primitives
Concepts
Point
.word xcoord
.word ycoord
Rect
.word x1
.word y1
.word x2
.word y2
Pattern
A simple repeating 8x8 pattern is defined by 8 bytes. All bits of each byte are used.
.byte row0
.byte row1
.byte row2
.byte row3
.byte row4
.byte row5
.byte row6
.byte row7
MapInfo
Used with GrafPorts to define offsets/clipping, and bitmaps for source data.
Point viewloc
.addr mapbits $2000 for the screen, or bitmap bits
.byte mapwidth $80, or stride for bitmap
.byte reserved
Rect maprect a.k.a. cliprect
GrafPort
There is always a current GrafPort (or "port" for short) that defines the destination and pen state of drawing operations.
MapInfo portmap
Pattern penpattern
.byte colormask_and
.byte colormask_or
Point penloc
.byte penwidth horizontal pen thickness
.byte penheight vertical pen thickness
.byte penmode
.byte textback text background
.addr textfont
PolyList
.byte count number of vertices in this polygon
.byte last high bit set if there are more polygons
Point vertex0
... repeats for each vertex
... repeats for each polygon
Font
This is a MousePaint-compatible font. Single- and double-width fonts are supported; max height is 16 pixels.
.byte fonttype 0=regular, $80=double-width
.byte lastchar char code of last character (usually $7F)
.byte height pixels (1-16)
.res N charwidth pixels, for each char
.res N row0 bits
.res N row0right bits (double-width only)
... repeats for each row
Commands
NoOp ($00)
No-op
No parameters.
Initialization
InitGraf ($01)
No parameters.
SetSwitches ($02)
Configure display switches
Parameters:
.byte flags bit 0=hires, 1=page2, 2=mixed, 3=text
GrafPort - assign, update, query ports
InitPort ($03)
Initialize GrafPort to standard values
Parameters:
(input is address of GrafPort record)
SetPort ($04)
Set current port as specified
Parameters:
(input is address of GrafPort record)
GetPort ($05)
Get pointer to current port
Parameters:
.addr port (out)
SetPortBits ($06)
Set just the mapinfo (viewloc, mapbits) of the current grafport.
Parameters:
(input is address of MapInfo record)
SetPenMode ($07)
Set the pen mode of the current grafport.
Parameters:
.byte mode pen*/notpen*
SetPattern ($08)
Set the pattern of the current grafport.
Parameters:
.res 8 pattern 8x8 pixel pattern for PaintRect calls
SetColorMasks ($09)
Set the color masks of the current grafport.
Parameters:
.byte and_mask
.byte or_mask
SetPenSize ($0A)
Set the pen size of the current grafport.
Parameters:
.byte penwidth horizontal pen thickness
.byte penheight vertical pen thickness
SetFont ($0B)
Set the font of the current grafport.
Parameters:
.addr textfont font definition
SetTextBG ($0C)
Set the text background of the current grafport.
Parameters:
.byte backcolor 0=black, $7F=white
Drawing - draw lines; frame, fill, and test rects and polys
Move ($0D)
Set pen location (relative) of the current grafport.
Parameters:
.word xdelta
.word ydelta
MoveTo ($0E)
Set pen location (absolute) of the current grafport.
Parameters:
Point pos
Line ($0F)
Draw line from pen location (relative) of the current grafport.
Parameters:
.word xdelta
.word ydelta
LineTo ($10)
Draw line from pen location (absolute) of the current grafport.
Parameters:
Point pos
PaintRect ($11)
Fill rectangle with pattern of the current grafport.
Parameters:
Rect rect
FrameRect ($12)
Draw rectangle with pen mode/size of the current grafport.
Parameters:
Rect rect
InRect ($13)
Is current position in bounds? A=$80 true, 0 false
Parameters:
Rect rect
PaintBits ($14)
Draw bitmap.
Parameters:
(input is address of MapInfo record)
PaintPoly ($15)
Fill multiple closed polygons with the pattern of the current grafport.
Parameters:
(input is address of PolyList record)
FramePoly ($16)
Draw multiple closed polygons with the pen mode/size of the current grafport.
Parameters:
(input is address of PolyList record)
InPoly ($17)
Is pen location of the current grafport within the polygon? A=$80 true, 0 false
Parameters:
(input is address of PolyList record)
Text - draw and measure text
TextWidth ($18)
Measure the width of a string in pixels
Parameters:
.addr data
.byte length
.word width (out) result in pixels
DrawText ($19)
Draw string at the pen location of the current graphport (as left, baseline)
Parameters:
.addr data
.byte length
Utility - configuration and version
SetZP1 ($1A)
Configure lower half of ZP usage by API (speed vs. convenience)
Parameters:
.byte preserve 0=stash/no auto restore; 1=restore now and onward
SetZP2 ($1B)
Configure upper half ZP usage by API (speed vs. convenience)
Parameters:
.byte preserve 0=stash/no auto restore; 1=restore now and onward
Mouse Graphics
Concepts
Cursor
.res 24 bitmap 2x12 byte bitmap (XOR'd after mask)
.res 24 mask 2x12 byte mask (OR'd with screen)
.byte hotx hotspot coords (pixels)
.byte hoty
Event
.byte kind event_kind_*
.res 4
if kind
is event_kind_key_down
:
.byte kind event_kind_*
.byte key (ASCII code; high bit clear)
.byte modifiers (0=none, 1=open-apple, 2=solid-apple, 3=both)
.res 2 reserved
if kind
is event_kind_update:
.byte kind event_kind_*
.byte window_id
.res 3 reserved
otherwise:
.byte kind event_kind_*
.word mousex
.word mousey
event_kind_no_event := 0 ; No mouse or keypress
event_kind_button_down := 1 ; Mouse button was depressed
event_kind_button_up := 2 ; Mouse button was released
event_kind_key_down := 3 ; Key was pressed
event_kind_drag := 4 ; Mouse button still down
event_kind_apple_key := 5 ; Mouse button was depressed, modifier key down
event_kind_update := 6 ; Window update needed
event_modifier_open_apple := 1 << 0
event_modifier_solid_apple := 1 << 1
Menu
Menu Bar record:
.word count Number of menu bar items
.byte menu_id Menu identifier
.byte disabled Flag
.addr title Address of length-prefixed string
.addr menu Address of Menu record
.res 6 reserved Reserved
... repeats for each menu
Menu record:
.word count Number of items in menu
.res 5 reserved Reserved
.byte options bit 0=OA, 1=SA, 2=mark, 5=check, 6=filler, 7=disabled
.byte mark_char Custom mark character if mark option set
.byte char1 ASCII code of shortcut #1 (e.g. uppercase B); or 0
.byte char2 ASCII code of shortcut #2 (e.g. lowercase b, or same); or 0
.addr name Address of length-prefixed string
... repeats for each menu item
Window "winfo"
.byte id
.byte options option_*
.addr title
.byte hscroll scroll_option_*
.byte vscroll scroll_option_*
.byte hthumbmax
.byte hthumbpos
.byte vthumbmax
.byte vthumbpos
.byte status
.byte reserved
.word mincontwidth minimum content size (horizontal)
.word maxcontwidth maximum content size (horizontal)
.word mincontlength minimum content size (vertical)
.word maxcontlength maximum content size (vertical)
GrafPort windowport GrafPort record
.addr nextwinfo address of next lower window in stack
Windows have a content area which has the requested dimensions. Above this is an optional title bar which in turn has an optional close box. Within the content area are an optional resize box and optional scroll bars.
option_dialog_box := 1 << 0
option_go_away_box := 1 << 1
option_grow_box := 1 << 2
scroll_option_none := 0
scroll_option_present := 1 << 7
scroll_option_thumb := 1 << 6
scroll_option_active := 1 << 0
scroll_option_normal := scroll_option_present | scroll_option_thumb | scroll_option_active
Commands
Initialization
Version ($1C)
Get toolkit version
Parameters:
.byte (out) major
.byte (out) minor
.byte (out) patch
.byte (out) status
.word (out) number
StartDeskTop ($1D)
Inits state, registers interrupt handler, draws desktop
Parameters:
.byte machine ROM FBB3 ($06 = IIe or later)
.byte subid ROM FBC0 ($EA = IIe, $E0 = IIe enh/IIgs, $00 = IIc/IIc+)
.byte op_sys 0=ProDOS, 1=Pascal
.byte slot_num: Mouse slot, 0 = search (will be filled in)
.byte use_interrupts 0=passive, 1=interrupt
.addr sysfontptr
.addr savearea buffer for saving screen data (e.g. behind menus)
.word savesize bytes
StopDeskTop ($1E)
Deallocates interrupt, hides cursor
No parameters.
SetUserHook ($1F)
Parameters:
.byte hook_id 0=before, 1=after event checking
.addr routine_ptr 0=remove hook_id
AttachDriver ($20)
Install pointer driver; A=0 on success, $95 if mouse disabled
Parameters:
.addr hook Mouse hook routine to install
.addr mouse_state (out) Address of mouse state (.word x, y; .byte status)
ScaleMouse ($21)
Set mouse/screen scaling
Parameters:
.byte x_exponent x-scale factor for mouse, 0...3
.byte y_exponent y-scale factor for mouse, 0...3
KeyboardMouse ($22)
Next operation will be performed by keyboard
No parameters.
GetIntHandler ($23)
Get address of interrupt handler
Parameters:
.addr handler (out) Address of interrupt handler (after cld)
Cursor Manager - set, show, hide
SetCursor ($24)
Set cursor definition
Parameters:
(input is address of Cursor record)
ShowCursor ($25)
Return cursor to visibility
No parameters.
HideCursor ($26)
Cursor hidden until ShowCursor call
No parameters.
ObscureCursor ($27)
Cursor hidden until moved
No parameters.
GetCursorAddr ($28)
Get cursor definition
Parameters:
.addr definition (out) Address of cursor record
Event Manager - get, peek, post
CheckEvents ($29)
Process mouse/kbd if GetEvent will be delayed.
No parameters.
GetEvent ($2A)
Parameters:
(parameter is address of Event record)
FlushEvents ($2B)
No parameters.
PeekEvent ($2C)
Parameters:
(parameter is address of Event record)
PostEvent ($2D)
Post event to queue
Parameters:
(parameter is address of Event record)
SetKeyEvent ($2E)
If set, keypresses are ignored by Tool Kit
Parameters:
.byte handle_keys high bit set = ignore keyboard, otherwise check
Menu Manager - configure, enable, disable, select
InitMenu ($2F)
Configure characters used for menu glyphs. Optional. The defaults are solid=$1E, open=$1F, check=$1D, control=$01.
Parameters:
.byte solid_char char code to use for solid apple glyph
.byte open_char char code to use for open apple glyph
.byte check_char char code to use for checkmark glyph
.byte control_char char code to use for control key glyph
SetMenu ($30)
Configure (and draw) menu
Parameters:
(input is address of Menu Bar record)
MenuSelect ($31)
Enter modal loop for handling mouse-down on menu bar
Parameters:
.byte menu_id (out) Top level menu identifier, or 0 if none
.byte menu_item (out) Index (1-based) of item in menu, or 0 if none
MenuKey ($32)
Find menu item corresponding to keypress
Parameters:
.byte menu_id (out)
.byte menu_item (out)
.byte which_key
.byte key_mods bit 0=OA, bit 1=SA
HiliteMenu ($33)
Toggle highlight state of menu
Parameters:
.byte menu_id
DisableMenu ($34)
Disable/enable a menu. Effectively disables all items, but individual disable/enable states are restored when re-enabled.
Parameters:
.byte menu_id
.byte disable 0=enable, 1=disable
DisableItem ($35)
Disable/enable a specific item in a menu.
Parameters:
.byte menu_id
.byte menu_item
.byte disable 0=enable, 1=disable
CheckItem ($36)
Sets a specific menu item as checked.
Parameters:
.byte menu_id
.byte menu_item
.byte check 0=unchecked, 1=checked
SetMark ($37)
Sets a specific menu item as using a distinct mark character when checked.
Parameters:
.byte menu_id
.byte menu_item
.byte set_char 0=use checkmark, 1=use mark_char
.byte mark_char char code to use for mark
Window Manager - open, close, drag, grow, update
OpenWindow ($38)
Parameters:
(input is address of WInfo record)
CloseWindow ($39)
Parameters:
.byte window_id
CloseAll ($3A)
No parameters.
GetWinPtr ($3B)
Get pointer to window params by id; A=0 on success
Parameters:
.byte window_id
.addr window_ptr (out) winfo address
GetWinPort ($3C)
Get drawing state of window
Parameters:
.byte window_id
.addr port (out) grafport address
SetWinPort ($3D)
Update port of window
Parameters:
.byte window_id
.addr port GrafPort to copy from
BeginUpdate ($3E)
Respond to update event for window
Parameters:
.byte window_id
EndUpdate ($3F)
No parameters.
FindWindow ($40)
Parameters:
.word mousex screen coordinates
.word mousey
.byte which_area (out) area_*
.byte window_id (out) of window
FrontWindow ($41)
Get id of top window
Parameters:
.byte window_id (out) window, or 0 if none
SelectWindow ($42)
Make window topmost
Parameters:
.byte window_id
TrackGoAway ($43)
Parameters:
.byte clicked (out) 0 = cancelled, 1 = close
.byte ?? (out)
.byte ?? (out)
DragWindow ($44)
Parameters:
.byte window_id
.word dragx mouse coords
.word dragy
.byte moved (out) high bit set if moved, clear if not
GrowWindow ($45)
Parameters:
.byte window_id
.word mousex
.word mousey
.byte itgrew (out) 0 = no change, 1 = moved
ScreenToWindow ($46)
Map screen coords to content coords
Parameters:
.byte window_id
.word screenx
.word screeny
.word windowx (out)
.word windowy (out)
WindowToScreen ($47)
Map content coords to screen coords
Parameters:
.byte window_id
.word windowx
.word windowy
.word screenx (out)
.word screeny (out)
Control Manager - scrollbars
FindControl ($48)
Parameters:
.word mousex
.word mousey
.byte which_ctl ctl_*
.byte which_part part_*
SetCtlMax ($49)
Parameters:
.byte which_ctl ctl_*_scroll_bar
.byte ctlmax maximum value
TrackThumb ($4A)
Parameters:
.byte which_ctl ctl_*_scroll_bar
.word mousex
.word mousey
.byte thumbpos (out) 0...255
.byte thumbmobed (out) 0 = no change, 1 = moved
UpdateThumb ($4B)
Parameters:
.byte which_ctl ctl_*_scroll_bar
.byte thumbpos new position 0...250
ActivateCtl ($4C)
Activate/deactivate scroll bar
Parameters:
.byte which_ctl ctl_*_scroll_bar
.byte activate 0=deactivate, 1=activate
More
NOTE: Movable DA windows must maintain an offscreen_flag. If a window is moved so that the content area is entirely offscreen then various operations should be skipped because the window's box coordinates will not be set correctly. TODO: Figure out if this is just a bug in the DAs.
Application Use
Initialization
StartDeskTop
InitMenu
(if necessary; the defaults are sensible)SetMenu
- Run main loop until quit
StopDeskTop
Main Loop
GetEvent
- If
event_kind_button_down
orevent_kind_apple_key
:FindWindow
to figure out what was clicked- If
area_desktop
- ignore - If
area_menubar
- handle menu - If
area_dragbar
- handle window drag - If
area_grow_box
- handle window resize - If
area_close_box
- handle window close - If
area_content
:FindControl
- If
ctl_*_scroll_bar
- handle scrolling - If
ctl_dead_zone
- ignore - If
ctl_not_a_control
:- If not topmost:
SelectWindow
- Otherwise, handle content click per app
- If not topmost:
- If
event_kind_key_down
- handle key - If
event_kind_drag
:- TODO
- If
event_kind_update
:- Redraw contents of
window_id
- Redraw contents of
Redraw window
GetWinPort
- get pointer to window's portSetPort
- make it currentHideCursor
- if multiple drawing calls will be made- ... draw ...
ShowCursor
- if neededSetWinPort
- save attributes if desired
Handle Key
MenuKey
- If
menu_id
is not 0:- Dispatch for
menu_id
andmenu_item
HiliteMenu
to toggle state back off when done
- Dispatch for
- Otherwise:
- handle key press per app
Handle Menu
MenuSelect
to initiate menu modal loop- If
menu_id
is 0, done - Dispatch for
menu_id
andmenu_item
HiliteMenu
to toggle state back off when done
Handle Window Drag
SelectWindow
to make topmost if necessaryDragWindow
to initiate drag modal loop- Handle update events
- Redraw window content if not moved and was made topmost
- If canceled - done
- For DeskTop DAs:
- Call
JUMP_TABLE_REDRAW_ALL
. - If offscreen flag was not set, redraw desktop icons (
DESKTOP_REDRAW_ICONS
). - Set offscreen flag if window's
top
is greater than or equal to the screen bottom (191), clear otherwise. - If offscreen flag is not set, redraw window.
- Call
Handle Window Close
TrackGoAway
to initiate modal close loop- If canceled - done
CloseWindow
Handle Scrolling
- If
part_thumb
:TrackThumb
to initiate modal scroll loop- If thumb did not move - done
- Redraw window content
UpdateThumb
- If
part_page_*
:- Scroll by a "page"
- Redraw window content
UpdateThumb
- If
part_*_arrow
:- Scroll by a "line"
- Redraw window content
UpdateThumb
Handle Window Resize
GrowWindow
to initiate modal resize loop- If canceled - done
UpdateThumb
if needed to adjust scroll bars- Redraw window content
- For DeskTop DAs:
- Call
JUMP_TABLE_REDRAW_ALL
. - Call
DESKTOP_REDRAW_ICONS
.
- Call
Handle Update Events
- Repeat:
PeekEvent
- If not
event_kind_update
- exit these steps - Otherwise:
GetEvent
BeginUpdate
- If error, continue
- Otherwise:
- Redraw
window_id
's content EndUpdate
- Redraw