;
; dbx.dbx.s
;
; Managing dialogue box control types (MDW)
;
;  1994 Straylight
;

;----- Standard header ------------------------------------------------------

		GET	libs:header
		GET	libs:swis

;----- External dependencies ------------------------------------------------

		GET	sapphire:dbox
		GET	sapphire:msgs
		GET	sapphire:screen

;----- Main code ------------------------------------------------------------

		AREA	|Sapphire$$Code|,CODE,READONLY

; --- dbx_declare ---
;
; On entry:	R0 == dialogue box handle from dbox
;		R1 == pointer to dialogue box definition block
;
; On exit:	--
;
; Use:		Declares a dialogue box to be dbx-managed, and declares the
;		control types of all its controls.

		EXPORT	dbx_declare
dbx_declare	ROUT

		STMFD	R13!,{R1-R3,R14}	;Save some registers
		LDR	R14,[R0,#dbx__defn]	;Is there a dbx definition?
		STR	R1,[R0,#dbx__defn]	;Store the definition pointer
		CMP	R14,#0			;If so, this isn't zero
		BNE	%90dbx_declare		;So don't mess with handlers

		; --- Copy the registered event handler ---

		ADD	R1,R0,#dbox__proc	;Point to the event proc
		LDMIA	R1,{R1-R3}		;Load all the information
		ADD	R14,R0,#dbx__proc	;Point to my bit of data
		STMIA	R14,{R1-R3}		;Save the old handler away

		; --- Now set up the dbx handler ---

		ADR	R1,dbx__events		;Point to my event handler
		STR	R1,[R0,#dbox__proc]	;Save this as the new proc
		STR	R0,[R0,#dbox__R10]	;Pass dbox handle in R10
90dbx_declare	LDMFD	R13!,{R1-R3,PC}^	;Return to caller

		LTORG

; --- dbx_sendEvent ---
;
; On entry:	R0 == event code to send
;		R1-R7 == depend on the event code
;		R10 == dialogue box handle
;
; On exit:	C flag as set by event handler
;
; Use:		Sends an event to the specified dialogue box.  This is
;		intended to be used by control handlers, hence the unusual
;		placing of the dialogue handle in R10.

		EXPORT	dbx_sendEvent
dbx_sendEvent	ROUT

		STMFD	R13!,{R8-R10,R12,R14}	;Save some registers
		MOV	R9,R10			;Pass dialogue handle in R9
		LDR	R14,[R10,#dbx__defn]	;Is this dialogue box dbx'ed?
		CMP	R14,#0			;Yes -- then this isn't 0
		ADDEQ	R14,R10,#dbox__proc	;No -- point to real proc
		ADDNE	R14,R10,#dbx__proc	;Yes -- point to saved proc
		LDMIA	R14,{R8,R10,R12}	;Load the proc bitties
		ADDS	R0,R0,#0		;Clear the carry flag
		TEQ	R8,#0			;Is there a handler?
		MOV	R14,PC			;Set up return address
		MOVNE	PC,R8			;Call the handler then
		LDMFD	R13!,{R8-R10,R12,R14}	;Load the registers I saved
		ORRCSS	PC,R14,#C_flag		;If C set, set C on exit
		BICCCS	PC,R14,#C_flag		;If C clear, clear C on exit

		LTORG

; --- dbx__events ---
;
; On entry:	R0 == event code
;		R1-R7 == depend on event type
;		R10 == dialogue box handle
;
; On exit:	--
;
; Use:		Handles events for a dbx-managed dialogue box.

dbx__events	ROUT

		; --- Make sure it's an interesting event ---

		CMP	R0,#dbEvent_redraw	;Is it a redraw event?
		BEQ	dbx__redraw		;Handle redraws specially

		CMP	R0,#0			;Is icon handle in R0?
		BGE	%10dbx__events		;Yes -- handle cleverly

		CMP	R0,#dbEvent_help	;Test events with icon in R1
		CMPNE	R0,#dbEvent_save
		CMPNE	R0,#dbEvent_load
		CMPNE	R0,#dbEvent_menu
		BEQ	%20dbx__events		;If any of them, handle it

		CMP	R0,#dbEvent_drag	;And now ones with icon in R2
		CMPNE	R0,#dbEvent_key
		BEQ	%30dbx__events

		; --- Don't recognise the event ---
		;
		; So we'd better pass it to the original dbox handle

		B	dbx_sendEvent		;This handles everything!

		; --- Handle mouse click events ---

10dbx__events	STMFD	R13!,{R0-R2,R14}	;Save some registers away
		MOV	R2,R1			;Get mouse button state
		MOV	R1,R0			;Get the icon clicked
		MOV	R0,#dbxEvent_click	;Give control a click event
		BL	dbx__ctrlEvent		;Send it to the control
		LDMFD	R13!,{R0-R2,R14}	;Restore all the registers
		B	%80dbx__events		;Tidy up things with C flag

		; --- Handle events with icon handle in R1 ---

20dbx__events	STMFD	R13!,{R0-R5,R14}	;Save a load of registers
		CMP	R0,#dbEvent_menu	;Is this a menu click event?
		MOVEQ	R0,#dbxEvent_click	;Yes -- then give a click
		MOVEQ	R2,#2			;And set the `menu' bit

		MOV	R5,#dbxDrop_load	;Assume event is a load
		CMP	R0,#dbEvent_save	;Is this a save event?
		MOVEQ	R5,#dbxDrop_save	;Yes -- it's a save instead
		CMPNE	R0,#dbEvent_load	;Or maybe it's a load event
		MOVEQ	R0,#dbxEvent_drop	;It's a file dropped event

		CMP	R0,#dbEvent_help	;In that case, it's a help?
		MOVEQ	R0,#dbxEvent_help	;Yes -- set up that event

		BL	dbx__ctrlEvent		;Send it to the control
		LDMFD	R13!,{R0-R5,R14}	;Restore a load of registers
		B	%80dbx__events		;And tidy everything up

		; --- And now handle the oddities with handles in R2 ---
		;
		; Both of these work just the same -- swap R2 and R1 over,
		; load event code into R0 and dispatch the event

30dbx__events	STMFD	R13!,{R0-R2,R14}	;Save some registers away
		EOR	R1,R1,R2		;The standard swap-in-three
		EOR	R2,R1,R2		;R2 == old_R1 now
		EOR	R1,R1,R2		;R1 == old_R2 now.  Done!
		CMP	R0,#dbEvent_drag	;Was it a drag event?
		MOVEQ	R0,#dbxEvent_click	;Yes -- deliver a click
		MOVNE	R0,#dbxEvent_key	;No -- deliver a keypress
		BL	dbx__ctrlEvent		;Send it to the control
		LDMFD	R13!,{R0-R2,R14}	;Restore the registers

		; --- Now handle the standard aftermath ---
		;
		; If the control didn't like it, we pass the whole event on
		; to the user dialogue box handler.

80dbx__events	BCC	dbx_sendEvent		;Send event to user if nec.
		ORRS	PC,R14,#C_flag		;Otherwise, we claim it

		LTORG

; --- dbx_findData ---
;
; On entry:	R0 == icon handle
;		R10 == dialogue box handle
;
; On exit:	If found, CS and
;		  R8 == pointer to writable control data
;		  R9 == pointer to static control data
;		else CC and
;		  R8, R9 corrupted
;
; Use:		Allows a control to find its data when called by client
;		code.

		EXPORT	dbx_findData
dbx_findData	ROUT

		STMFD	R13!,{R4-R7,R14}	;Save some registers
		LDR	R9,[R10,#dbx__defn]	;Find the dialogue def block
10dbx_findData	LDMIA	R9,{R4-R8}		;Load all the information
		CMP	R4,#-1			;Is the icon handle -1?
		BEQ	%80dbx_findData		;Yes -- icon handle not found
		CMP	R1,R4			;Is this a match we have?
		ADDNE	R9,R9,R7		;No -- add in the block size
		BNE	%10dbx_findData		;And loop around again

		; --- Find control's workspace if necessary ---
		;
		; If the user has not supplied control writable data and
		; it wants some, an address exception is created.

		ADD	R9,R9,#16		;Point past this block header
		TST	R6,#dbxFlag_dataR10 :OR: dbxFlag_dataR12
		MOVEQ	R8,#&80000000		;Address exception if wanted
		BEQ	%15dbx_findData		;No data -- skip onwards

		ADD	R9,R9,#4		;Skip past data offset word
		TST	R6,#dbxFlag_dataR10	;Does he want R10-relative?
		LDRNE	R14,[R10,#dbx__R10]	;Yes -- load user's R10 value
		LDREQ	R14,[R10,#dbx__R12]	;No -- load user's R12 value
		ADD	R8,R14,R8		;Add in loaded offset nicely

15dbx_findData	LDMFD	R13!,{R4-R7,R14}	;Unstack registers
		ORRS	PC,R14,#C_flag		;Say we found it OK

80dbx_findData	LDMFD	R13!,{R4-R7,R14}	;Unstack registers
		BICS	PC,R14,#C_flag		;Say we couldn't find it

		LTORG

; --- dbx__ctrlEvent ---
;
; On entry:	R0 == dbx event code type
;		R1 == icon handle to dispatch to
;		R2-R7 == depend on the event code
;		R10 == dialogue box handle
;
; On exit:	Registers preserved, C set if control claimed the event
;
; Use:		Sends an event to a control, setting up all the registers
;		etc. appropriately.

dbx__ctrlEvent	ROUT

		STMFD	R13!,{R4-R9,R12,R14}	;Save masses of registers

		; --- Locate the icon in the control block ---

		LDR	R9,[R10,#dbx__defn]	;Find the dialogue def block
10		LDMIA	R9,{R4-R8}		;Load all the information
		CMP	R4,#-1			;Is the icon handle -1?
		BEQ	%80dbx__ctrlEvent	;Yes -- icon handle not found
		CMP	R1,R4			;Is this a match we have?
		ADDNE	R9,R9,R7		;No -- add in the block size
		BNE	%10dbx__ctrlEvent	;And loop around again

		; --- We have found the control information ---
		;
		; We'd better make sure the control wants the event

		BL	dbx__xform		;Translate R5 nicely
		LDMIA	R5,{R7,R12,R14}		;Load control R12 and flags
		CMP	R7,#0			;Is there an address?
		LDRNE	R7,[R7,#0]		;Load workspace offset
		LDRNE	R12,[R11,-R12]		;Load workspace base address
		ADDNE	R12,R12,R7		;And work out workspace
		MOV	R7,#1			;To shift the bit around
		TST	R14,R7,LSL R0		;Check event's mask bit
		BEQ	%80dbx__ctrlEvent	;Bit is clear -- ignore event

		; --- Find control's workspace if necessary ---
		;
		; If the user has not supplied control writable data and
		; it wants some, an address exception is created.

		ADD	R9,R9,#16		;Point past this block header
		TST	R6,#dbxFlag_dataR10 :OR: dbxFlag_dataR12
		MOVEQ	R8,#&80000000		;Address exception if wanted
		BEQ	%15dbx__ctrlEvent	;No data -- skip onwards

		ADD	R9,R9,#4		;Skip past data offset word
		TST	R6,#dbxFlag_dataR10	;Does he want R10-relative?
		LDRNE	R14,[R10,#dbx__R10]	;Yes -- load user's R10 value
		LDREQ	R14,[R10,#dbx__R12]	;No -- load user's R12 value
		ADD	R8,R14,R8		;Add in loaded offset nicely

		; --- Writable data pointer is set up then ---

15		MOV	R14,PC			;Set up return address nicely
		ADD	PC,R5,#12		;Call the control's code

		LDMFD	R13!,{R4-R9,R12,R14}	;Restore all the registers
		ORRCSS	PC,R14,#C_flag		;If C set, set C on return
		BICCCS	PC,R14,#C_flag		;Otherwise clear C on return

		; --- We couldn't find a suitable control ---

80		LDMFD	R13!,{R4-R9,R12,R14}	;Restore all the registers
		BICS	PC,R14,#C_flag		;Clear C -- event ignored

		LTORG

; --- dbx__xform ---
;
; On entry:	R5 == pointer to a dbx control
;
; On exit:	R5 possibly modified
;
; Use:		Translates R5 to point to a dbx control block.  The problem
;		is dynamic linking: R5 might actually point to a branch
;		to the real control.  So we spot that here and hack around
;		the problem.

dbx__xform	ROUT

		STMFD	R13!,{R14}		;Save a register
		LDR	R14,[R5,#0]		;Load the pointer out
		CMP	R14,#&80000000		;Is the pointer out of range?
		BICCS	R14,R14,#&FF000000	;Clear instruction bits
		ADDCS	R14,R14,#2		;Account for pipeline
		ADDCS	R5,R5,R14,LSL #2	;And work out the address
		LDMFD	R13!,{PC}^		;And return to caller

		LTORG

; --- dbx__redraw ---
;
; On entry:	R0 == dbEvent_redraw
;		R1 == pointer to redraw rectangle block
;		R2 == x coordinate of window origin on screen
;		R3 == y coordinate of window origin on screen
;		R10 == dialogue box handle
;
; On exit:	Registers preserved, C clear on exit unless user claimed
;		the redraw event.
;
; Use:		Handles a redraw event for a dbx-controlled dialogue box.
;		We go through all the controls in the block and test which
;		ones want redraw events.  For each one, we set the graphics
;		rectangle to the intersection of the icon bounding box and
;		the redraw rectangle, load the screen position of the icon
;		and pass the control handler a redraw event.

dbx__redraw	ROUT

		STMFD	R13!,{R14}		;Save return address
		BL	dbx_sendEvent		;Let the user do some redraw
		LDMCSFD	R13!,{PC}		;If it was claimed, return
		STMFD	R13!,{R0-R9,R12}	;Save some more registers

		; --- Set up some standard registers ---

		MOV	R6,R2			;Look after the origin coords
		MOV	R7,R3			;Both x and y -- we need 'em
		ADD	R5,R1,#28		;Point to redraw rectangle

		LDR	R0,[R10,#dbx__defn]	;Find the control definitions

		; --- Now loop through the controls ---

10dbx__redraw	LDMIA	R0,{R1-R4,R8}		;Load the control information
		CMP	R1,#-1			;Is this the end of the list?
		BEQ	%90dbx__redraw		;Yes -- return to caller

		; --- Check if the control likes redraw events ---

		LDR	R14,[R2,#0]		;Load the value out
		CMP	R14,#&80000000		;Is it out of range?
		BICCS	R14,R14,#&ff000000	;Yes -- clear instruction
		ADDCS	R14,R14,#2		;Compensate for pipeline
		ADDCS	R2,R2,R14,LSL #2	;And work out real address
		LDMIA	R2,{R9,R12,R14}		;Load control R12 and flags
		CMP	R9,#0			;Is there an address?
		LDRNE	R9,[R9,#0]		;Load workspace offset
		LDRNE	R12,[R11,-R12]		;Load workspace base
		ADDNE	R12,R12,R9		;Work out workspace address
		TST	R14,#1<<dbxEvent_redraw	;Is the mask bit set for 'em?
		ADDEQ	R0,R0,R4		;No -- move to next one
		BEQ	%10dbx__redraw		;And loop back round again

		; --- It does -- spring into action then ---

		ADD	R9,R0,#16		;Point past this block header
		TST	R3,#dbxFlag_dataR10 :OR: dbxFlag_dataR12
		MOVEQ	R8,#&80000000		;Address exception if wanted
		BEQ	%15dbx__redraw		;No data -- skip onwards

		ADD	R9,R9,#4		;Skip past data offset word
		TST	R3,#dbxFlag_dataR10	;Does he want R10-relative?
		LDRNE	R14,[R10,#dbx__R10]	;Yes -- load user's R10 value
		LDREQ	R14,[R10,#dbx__R12]	;No -- load user's R12 value
		ADD	R8,R14,R8		;Add in loaded offset nicely

		; --- Registers R8 onwards are all set up then ---

15dbx__redraw	STMFD	R13!,{R0,R2-R5}		;Save some more registers
		LDR	R0,[R10,#dbox__defn]	;Load the window def pointer
		ADD	R0,R0,#88		;Point to the first icon
		ADD	R0,R0,R1,LSL #5		;Point to R1th icon
		LDMIA	R0,{R2-R5,R14}		;Load icon coordinates
		ADD	R2,R2,R6		;Convert them to screen ones
		ADD	R3,R3,R7
		ADD	R4,R4,R6
		ADD	R5,R5,R7

		; --- Trim icon so all coords are inclusive ---

		STMFD	R13!,{R6-R10}		;Save some temp regs too
		TST	R14,#4			;Does icon have a border?
		BL	screen_getInfo		;Get the current screen info
		ADD	R0,R0,#screen_dx	;Point to the pixel sizes
		LDMIA	R0,{R10,R14}		;Load the pixel sizes out
		SUB	R4,R4,R10		;Chop off the extra x pixel
		SUB	R5,R5,R14		;Chop off the y one too
		SUBNE	R4,R4,R10		;If border, take off an...
		SUBNE	R5,R5,R14		;... extra pixel all the...
		ADDNE	R2,R2,R10		;... way round to stop...
		ADDNE	R3,R3,R14		;... nasty flickery effects

		; --- Now load the graphics window and compare ---

		LDR	R6,[R13,#36]		;Load the rectangle pointer
		LDMIA	R6,{R6-R9}		;Load the rectangle coords
		SUB	R8,R8,R10		;Trim these coordinates too
		SUB	R9,R9,R14
		CMP	R2,R8			;Check they overlap
		CMPLE	R3,R9
		CMPLE	R6,R4
		CMPLE	R7,R5
		BGT	%70dbx__redraw		;And skip to the end

		; --- Now construct the intersection rectangle ---

		STMFD	R13!,{R6-R9}		;Save these coordinates away
		CMP	R6,R2
		MOVLT	R6,R2
		CMP	R7,R3
		MOVLT	R7,R3
		CMP	R8,R4
		MOVGT	R8,R4
		CMP	R9,R5
		MOVGT	R9,R5

		; --- Set this as the graphics rectangle ---

		MOV	R6,R6,LSL #8		;Shift x0 up one byte
		ORR	R6,R6,#24		;Set graphics rectangle code
		ORR	R6,R6,R7,LSL #24	;Move in bottom byte of y0
		MOV	R7,R7,LSR #8		;Get top byte of y0
		ORR	R7,R7,R8,LSL #8		;Move in both bytes of x1
		ORR	R7,R7,R9,LSL #24	;Move in bottom byte of y1
		MOV	R8,R9,LSR #8		;Get top byte of y1
		STMFD	R13!,{R1,R6-R8}		;Save that lot on the stack
		ADD	R0,R13,#4		;Point to VDU sequence
		MOV	R1,#9			;Length of the sequence
		SWI	OS_WriteN		;Write them to the VDU
		LDMFD	R13!,{R1}		;Restore R1 from the stack
		ADD	R13,R13,#12		;Reclaim stack from VDU op

		; --- Now call the control's event handler ---

		ADD	R14,R13,#24		;Point to old saved registers
		LDMIA	R14!,{R8-R10}		;Restore arguments for event
		LDR	R6,[R13,#52]		;Load graphics window pointer
		LDR	R0,[R14,#4]		;Get the control handler ptr
		ADD	R0,R0,#12		;Point to the handler code
		STMFD	R13!,{R0}		;Save it on the stack
		MOV	R0,#dbxEvent_redraw	;Give it a redraw event code
		MOV	R14,PC			;Set up the return address
		LDMFD	R13!,{PC}		;Call the routine nicely

		; --- Tidy everything up once more ---

		LDMFD	R13!,{R6-R9}		;Get the old graphics window
		MOV	R6,R6,LSL #8		;Shift x0 up one byte
		ORR	R6,R6,#24		;Set graphics rectangle code
		ORR	R6,R6,R7,LSL #24	;Move in bottom byte of y0
		MOV	R7,R7,LSR #8		;Get top byte of y0
		ORR	R7,R7,R8,LSL #8		;Move in both bytes of x1
		ORR	R7,R7,R9,LSL #24	;Move in bottom byte of y1
		MOV	R8,R9,LSR #8		;Get top byte of y1
		STMFD	R13!,{R6-R8}		;Save that lot on the stack
		MOV	R0,R13			;Point to VDU sequence
		MOV	R1,#9			;Length of the sequence
		SWI	OS_WriteN		;Restore graphics window
		ADD	R13,R13,#12		;Reclaim stack from VDU op

70dbx__redraw	LDMFD	R13!,{R6-R10}		;Restore main code's R6-R10
		LDMFD	R13!,{R0,R2-R5}		;Restore variables for loop
		ADD	R0,R0,R4		;Move on to the next block
		B	%10dbx__redraw		;Go back to the main loop

		; --- Return to the caller ---

90dbx__redraw	LDMFD	R13!,{R0-R9,R12,R14}	;Restore a load of registers
		BICS	PC,R14,#C_flag		;Return without claiming

		LTORG

; --- dbx_controlBBox ---
;
; On entry:	R0 == dialogue box handle
;		R1 == control icon number
;
; On exit:	R0,R1 preserved
;		R2-R5 == inclusive screen coordinates of icon bounding box
;
; Use:		Calculates the position *on the screen* of the given control
;		icon, and returns it to you as a set of four inclusive
;		coordinates (*not* inclusive-exclusve as the WIMP tends to
;		return to you)

		EXPORT	dbx_controlBBox
dbx_controlBBox	ROUT

		STMFD	R13!,{R0,R1,R6,R7,R14}	;Save a load of registers
		MOV	R7,R0			;Look after the dbox handle
		LDR	R0,[R0,#dbox__defn]	;Find the window definition
		ADD	R0,R0,#88		;Find the first icon defn
		ADD	R0,R0,R1,LSL #5		;Find the correct icon defn
		LDMIA	R0,{R2-R6}		;Load coordinates and flags
		TST	R6,#4			;Does the icon have a border?

		BL	screen_getInfo		;Find info about the screen
		ADD	R0,R0,#screen_dx	;Point to the pixel sizes
		LDMIA	R0,{R0,R1}		;Load the pixel sizes

		SUB	R4,R4,R0		;Get the inclusive coords
		SUB	R5,R5,R1
		SUBNE	R4,R4,R0		;If border, move inwards
		SUBNE	R5,R5,R1
		ADDNE	R2,R2,R0
		ADDNE	R3,R3,R1

		LDR	R0,[R7,#dbox__window]	;Get the dbox's window handle
		SUB	R13,R13,#36		;Make way for icon state blk
		STR	R0,[R13,#0]		;Save the window handle in it
		MOV	R1,R13			;Point at the block
		SWI	Wimp_GetWindowState	;Get all the window info

		LDR	R6,[R1,#4]		;Get the min x coordinate
		ADD	R1,R1,#16		;Point to the max y coord
		LDMIA	R1,{R0,R7,R14}		;Load the other coords I want
		SUB	R6,R6,R7		;Get the x origin position
		SUB	R7,R0,R14		;Get the y origin position

		ADD	R2,R2,R6		;Convert icon posn to screen
		ADD	R3,R3,R7
		ADD	R4,R4,R6
		ADD	R5,R5,R7

		ADD	R13,R13,#36		;Reclaim that stack I used
		LDMFD	R13!,{R0,R1,R6,R7,PC}^	;Return to caller happy

		LTORG

; --- dbx_update ---
;
; On entry:	R0 == dialogue box handle
;		R1 == icon number of control to update
;
; On exit:	--
;
; Use:		Redraws the specified control immediately.  If the control
;		does not redraw itself, this call does nothing.

		EXPORT	dbx_update
dbx_update	ROUT

		STMFD	R13!,{R2,R14}		;Save some registers
		MOV	R2,#dbxEvent_redraw	;Send a redraw event
		BL	dbx__update		;Perform the redraw
		LDMFD	R13!,{R2,PC}^		;And return to caller

		LTORG

; --- dbx_qUpdate ---
;
; On entry:	R0 == dialogue box handle
;		R1 == icon number of control to update
;
; On exit:	--
;
; Use:		Makes a control quickly update itself in whichever way it
;		needs to in order to be perfect again.  It is anticipated
;		that this is used to update EORed areas of the control.

		EXPORT	dbx_qUpdate
dbx_qUpdate	ROUT

		STMFD	R13!,{R2,R14}		;Save some registers
		MOV	R2,#dbxEvent_update	;Send an update event
		BL	dbx__update		;Perform the redraw
		LDMFD	R13!,{R2,PC}^		;And return to caller

		LTORG

; --- dbx__update ---
;
; On entry:	R0 == dialogue box handle
;		R1 == icon number of control to update
;		R2 == event to send to control
;
; On exit:	--
;
; Use:		Sends events to a control to perform an update.  This is used
;		for dbx_update and for dbx_qUpdate.

dbx__update	ROUT

		STMFD	R13!,{R0-R10,R12,R14}	;Save a large number of regs
		MOV	R10,R0			;Look after the dbox handle

		; --- Try to find the control ---

		LDR	R9,[R10,#dbx__defn]	;Find the dialogue def block
10dbx__update	LDMIA	R9,{R4-R8}		;Load all the information
		CMP	R4,#-1			;Is the icon handle -1?
		BEQ	%80dbx__update		;Yes -- icon handle not found
		CMP	R1,R4			;Is this a match we have?
		ADDNE	R9,R9,R7		;No -- add in the block size
		BNE	%10dbx__update		;And loop around again

		; --- We have found the control ---
		;
		; Check that it supports redraw events.

		BL	dbx__xform		;Translate the pointer
		LDMIA	R5,{R4,R12,R14}		;Load control R12 and flags
		CMP	R4,#0			;Is there any workspace?
		LDRNE	R4,[R4,#0]		;Load workspace offset
		LDRNE	R12,[R11,-R12]		;Load workspace base
		ADDNE	R12,R12,R4		;And work out workspace
		MOV	R4,#1			;A value to shift with
		TST	R14,R4,LSL R2		;Check it wants the event
		BEQ	%80dbx__update		;No -- skip to the end

		; --- Now find the control's workspace ---

		ADD	R9,R9,#16		;Point past this block header
		TST	R6,#dbxFlag_dataR10 :OR: dbxFlag_dataR12
		MOVEQ	R8,#&80000000		;Address exception if wanted
		BEQ	%15dbx__update		;No data -- skip onwards

		ADD	R9,R9,#4		;Skip past data offset word
		TST	R6,#dbxFlag_dataR10	;Does he want R10-relative?
		LDRNE	R14,[R10,#dbx__R10]	;Yes -- load user's R10 value
		LDREQ	R14,[R10,#dbx__R12]	;No -- load user's R12 value
		ADD	R8,R14,R8		;Add in loaded offset nicely

		; --- Now we need to find the icon definition ---

15dbx__update	ADD	R5,R5,#12		;Point to the control handler
		STMFD	R13!,{R5}		;Save control handler ptr
		LDR	R0,[R10,#dbox__defn]	;Load the window def pointer
		ADD	R0,R0,#88		;Point to the first icon
		ADD	R0,R0,R1,LSL #5		;Point to R1th icon
		LDMIA	R0,{R2-R6}		;Load icon coordinates
		SUB	R13,R13,#44		;Make way for a redraw blk
		LDR	R14,[R10,#dbox__window]	;Get the dialogue's window
		STR	R14,[R13,#0]		;Store it in the block
		STMIB	R13,{R2-R5}		;Store icon coordinates too

		; --- Start the window update ---

		MOV	R1,R13			;Point to the update block
		SWI	Wimp_UpdateWindow	;Give me a first rectangle
		CMP	R0,#0			;Is there anything to do?
		BEQ	%70dbx__update		;No -- skip to loop bottom

		; --- Fix the icon bounding box to be inclusive ---

		TST	R6,#4			;Does icon have a border?
		BL	screen_getInfo		;Get the screen information
		ADD	R0,R0,#screen_dx	;Point to the pixel sizes
		LDMIA	R0,{R6,R7}		;Get the pixel sizes
		SUB	R4,R4,R6		;Chop off the extra x pixel
		SUB	R5,R5,R7		;Chop off the y one too
		SUBNE	R4,R4,R6		;If border, take off an...
		SUBNE	R5,R5,R7		;... extra pixel all the...
		ADDNE	R2,R2,R6		;... way round to stop...
		ADDNE	R3,R3,R7		;... nasty flickery effects

		; --- Now translate the whole thing to window coords ---

		LDR	R6,[R1,#4]		;Get the window left position
		ADD	R0,R1,#16		;Point to the top position
		LDMIA	R0,{R0,R7,R14}		;Load top, and scroll posns
		SUB	R6,R6,R7		;Convert to find origin x
		SUB	R7,R0,R14		;Convert to find origin y
		ADD	R2,R2,R6		;Convert rectangle now
		ADD	R3,R3,R7
		ADD	R4,R4,R6
		ADD	R5,R5,R7
		ADD	R6,R13,#28		;Load graphic window pointer

		; --- Now do the main update loop ---

20dbx__update	LDR	R1,[R13,#52]		;Load control's icon handle
		LDR	R0,[R13,#56]		;And the event which we send
		MOV	R14,PC			;Set up the return address
		LDR	PC,[R13,#44]		;Call the control routine
		MOV	R1,R13			;Point to the update block
		SWI	Wimp_GetRectangle	;Get the next rectangle
		CMP	R0,#0			;Are there any more left?
		BNE	%20dbx__update		;Yes -- loop round again

		; --- Tidy up the stack and registers ---

70dbx__update	ADD	R13,R13,#48		;Restore all the stack

		; --- Return to caller ---

80dbx__update	LDMFD	R13!,{R0-R10,R12,PC}^	;Return to caller at last

		LTORG

;----- Dialogue box blocks --------------------------------------------------

		^	0

; --- Information for dbox ---

dbox__window	#	4			;The real window handle
dbox__proc	#	4			;Pointer to event handler
dbox__R10	#	4			;Magic handle for event proc
dbox__R12	#	4			;Workspace for event proc
dbox__oldCaret	#	24			;Caret position to restore
dbox__defn	#	4			;Pointer to window template
dbox__template	#	4			;Pointer to original template
dbox__title	#	4			;Embedded title icon number
dbox__flags	#	4			;Various interesting flags

; --- Information for dbx ---

dbx__proc	#	4			;Pointer to user event proc
dbx__R10	#	4			;Object pointer for user proc
dbx__R12	#	4			;Workspace for user proc
dbx__defn	#	4			;Pointer to control def block

dbox__blockSize	#	0			;Size of the above block

;----- dbx dialogue definition ----------------------------------------------

		^	0
dbx__icon	#	4			;Icon number of this control
dbx__control	#	4			;Pointer to control type
dbx__dbFlags	#	4			;Flags for the control
dbx__size	#	4			;Size of this control info
dbx__data	#	4			;(Optional) offset to data

dbxFlag_dataR10	EQU	(1<<0)			;Has R10-relative data
dbxFlag_dataR12	EQU	(1<<1)			;Has R12-relative data

;----- dbx control definition -----------------------------------------------

		^	0
dbx__ctrlR12	#	4			;Workspace for control
dbx__ctrlFlags	#	4			;Flags mask for the control
dbx__handler	#	4			;The actual handler code

;----- dbx event codes ------------------------------------------------------

		^	0
dbxEvent_click	#	1
dbxEvent_redraw	#	1
dbxEvent_key	#	1
dbxEvent_drop	#	1
dbxEvent_help	#	1
dbxEvent_update	#	1

		^	0
dbxDrop_load	#	1
dbxDrop_save	#	1

;----- That's all, folks ----------------------------------------------------

		END
