;
; dbox.s
;
; Dialogue box handling (MDW)
;
;  1994-1998 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; This file is part of Straylight's Sapphire library.
;
; Sapphire is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2, or (at your option)
; any later version.
;
; Sapphire is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with Sapphire.  If not, write to the Free Software Foundation,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

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

		GET	libs:header
		GET	libs:swis

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

		GET	sapphire:akbd
		GET	sapphire:alloc
		GET	sapphire:event
		GET	sapphire:keyMap
		GET	sapphire:help
		GET	sapphire:hour
		GET	sapphire:msgs
		GET	sapphire:sapphire
		GET	sapphire:string
		GET	sapphire:subAlloc
		GET	sapphire:template
		GET	sapphire:transWin
		GET	sapphire:win
		GET	sapphire:winUtils

;----- Creating and deleting dialogue boxes ---------------------------------

		AREA	|Sapphire$$Code|,CODE,READONLY

; --- dbox_create ---
;
; On entry:	R0 == pointer to dialogue template name
;
; On exit:	R0 == dialogue box handle for the dialogue
;		May return an error
;
; Use:		Creates a dialogue box from a template definition.

		EXPORT	dbox_create
dbox_create	ROUT

		STMFD	R13!,{R1-R3,R14}	;Save some registers

		; --- Locate the template and copy it ---

		MOV	R3,R0			;Keep name pointer safe
		MOV	R1,#0			;No template created yet
		BL	template_find		;Find the actual definition
		MOVVC	R2,R0			;Keep this pointer
		MOVVS	R2,#1			;Otherwise assume shared rsc
		MOV	R0,R3			;Point at the name again
		BL	template_copy		;And create the copy I use
		MOVVC	R1,R0			;Look after the copy

		; --- Now create a dialogue box around it ---

		BLVC	dbox_fromDefn		;Create dbox from window def
		STRVC	R2,[R0,#dbox__template]	;Store the template pointer
		LDMVCFD	R13!,{R1-R3,R14}	;Unstack the registers
		BICVCS	PC,R14,#V_flag		;And return errorless

		; --- Tidy up aftet an error

		MOV	R2,R0			;Look after this
		MOVS	R0,R1			;Get the template pointer
		BLNE	template_free		;Maybe we free it
		MOVNE	R0,R2			;If not, get error back
		ADDEQ	R2,R2,#4		;Otherwise find error text
		ADREQ	R0,dbox__createErr	;Point to my skeleton error
		BLEQ	msgs_error		;Translate and substitute
		LDMFD	R13!,{R1-R3,R14}	;Restore registers
		ORRS	PC,R14,#V_flag		;Return the error

		LTORG

; --- dbox_fromEmbedded ---
;
; On entry:	R0 == pointer to an embedded template
;
; On exit:	R0 == dialogue box handle
;		May return an error
;
; Use:		Creates a dialogue box from an embedded template definition.

		EXPORT	dbox_fromEmbedded
dbox_fromEmbedded ROUT

		STMFD	R13!,{R1,R2,R14}	;Save some registers
		MOV	R1,#0			;Clear template pointer
		BL	template_embedded	;Copy the template
		MOVVC	R1,R0			;Look after this
		BLVC	dbox_fromDefn		;Create the dialogue box
		MOVVC	R14,#1			;Mark as a template
		STRVC	R14,[R0,#dbox__template] ;So it gets freed properly
		LDMVCFD	R13!,{R1,R2,R14}	;Restore registers
		BICVCS	PC,R14,#V_flag		;And return with no error

		MOV	R2,R0			;Look after this
		MOVS	R0,R1			;Get the template pointer
		BLNE	template_free		;Maybe we free it
		MOVNE	R0,R2			;If not, get error back
		ADDEQ	R2,R2,#4		;Otherwise find error text
		ADREQ	R0,dbox__createErr	;Point to my skeleton error
		BLEQ	msgs_error		;Translate and substitute
		LDMFD	R13!,{R1,R2,R14}	;Restore registers
		ORRS	PC,R14,#V_flag		;Return the error

		LTORG

; --- dbox_fromDefn ---
;
; On entry:	R0 == pointer to a window definition
;
; On exit:	R0 == dialogue box handle for the dialogue
;		May return an error
;
; Use:		Creates a dialogue box from an immediate window definition,
;		rather than a template.  There are several things you need
;		to be aware of when you use this call to create a dialogue
;		box:
;
;		* The window definition is not copied, but used directly
;		  for the duration the dialogue box exists.  It must
;		  not move for this duration.  When the dialogue is
;		  destroyed, you can release the memory for the definition,
;		  although this is your responsibility.
;
;		* The indirected data is not copied either, so you'll have
;		  to copy it yourself if you want multiple dialogues from
;		  the same window definition.
;
;		* The window definition and the indirected data must both
;		  be writable.

		EXPORT	dbox_fromDefn
dbox_fromDefn	ROUT

		STMFD	R13!,{R1-R3,R10,R14}	;Save some registers away

		; --- Obtain a dbox block from the heap ---

		MOV	R3,R0			;Look after the definition
		MOV	R0,#dbox__blockSize	;Find out how much I need
		BL	alloc			;Allocate the memory
		BLCS	alloc_error		;If it failed, find error msg
		BCS	%99dbox_fromDefn	;... and quit if no memory

		; --- Now start filling in the structure ---

		STR	R3,[R0,#dbox__defn]	;Store the copy pointer away
		MOV	R2,#0			;Start zeroing things
		STR	R2,[R0,#dbox__proc]	;No event handler yet
		STR	R2,[R0,#dbox__flags]	;Dialogue box has no flags
		STR	R2,[R0,#dbx__defn]	;Dbox not nabbed by dbx yet
		STR	R2,[R0,#dbox__template]	;No template definition
		MOV	R2,#-1			;No embedded title icon
		STR	R2,[R0,#dbox__title]	;So store it away
		MOV	R10,R0			;Keep this pointer safe

		; --- Now we need to create a window ---

		MOV	R1,R3			;Point to the window defn
		SWI	XWimp_CreateWindow	;Create the window
		BVS	%98dbox_fromDefn	;If it failed, tidy up
		STR	R0,[R10,#dbox__window]	;Store the window handle

		; --- Now register our event handler for it ---

		ADR	R1,dbox__events		;Point to my event handler
		MOV	R2,R10			;Pass the dialogue box handle
		WSPACE	dbox__wSpace,R3		;And my workspace pointer
		BL	win_eventHandler	;Register the event handler
		BVS	%97dbox_fromDefn	;If that failed, tidy up

		; --- Now return the dialogue box handle ---

		MOV	R0,R10			;Return pointer to my block
		LDMFD	R13!,{R1-R3,R10,R14}	;Restore the registers
		BICS	PC,R14,#V_flag		;Return with no errors

		; --- Tidy up after unfortunate events ---

97dbox_fromDefn	MOV	R3,R0			;Keep error pointer
		ADD	R1,R10,#dbox__window	;Point to the window handle
		SWI	Wimp_DeleteWindow	;Delete the duff window
		MOV	R0,R3			;Restore error pointer

98dbox_fromDefn	MOV	R2,R0			;Keep error pointer
		MOV	R0,R10			;Point to the block
		BL	free			;Free it up -- it's useless
		MOV	R0,R2			;Restore error pointer

99dbox_fromDefn	ADD	R2,R0,#4		;Point to the error message
		ADR	R0,dbox__createErr	;Point to my skeleton error
		BL	msgs_error		;Translate and substitute
		LDMFD	R13!,{R1-R3,R10,R14}	;Restore registers
		ORRS	PC,R14,#V_flag		;Return the error

dbox__createErr	DCD	1
		DCB	"dboxCRTERR",0

; --- dbox_destroy ---
;
; On entry:	R0 == dialogue box handle
;
; On exit:	--
;
; Use:		Destroys a dialogue box, freeing all the memory it took
;		up etc.

		EXPORT	dbox_destroy
dbox_destroy	ROUT

		STMFD	R13!,{R0-R3,R14}	;Save some registers

		; --- Make sure the dialogue's been closed ---

		BL	dbox_close		;Close the dialogue box

		; --- Remove the event handler ---

		MOV	R2,R0			;Move handle somewhere nicer
		LDR	R0,[R2,#dbox__window]	;Find the window handle
		BL	win_windowDeleted	;Window doesn't need handling

		; --- Delete the window ---

		ADD	R1,R2,#dbox__window	;Point to the window handle
		SWI	Wimp_DeleteWindow	;Delete the window

		; --- Free the template copy ---

		LDR	R14,[R2,#dbox__template] ;Load the template address
		CMP	R14,#0			;Is there one defined?
		LDRNE	R0,[R2,#dbox__defn]	;Point to the template copy
		BLNE	template_free		;Free it up now

		; --- Free the dialogue block ---

		MOV	R0,R2			;Point to the dbox block
		BL	free			;Free its memory up

		; --- Return to caller ---

		LDMFD	R13!,{R0-R3,PC}^	;Return to caller

;----- The event handler ---------------------------------------------------

; --- dbox__events ---
;
; On entry:	R0 == the event code that happened
;		R1 == pointer to the event data
;		R10 == dialogue box it happened to
;
; On exit:	CS if we handled the event, CC otherwise
;
; Use:		Handles various events for a dialogue box

dbox__events	ROUT

		; --- Dispatch the event to the right place ---

		STR	R10,dbox__eventDbox	;Remember this handle
		CMP	R0,#9			;Is it a sensible event?
		BGE	%00dbox__events		;No -- check for messages
		ADD	PC,PC,R0,LSL #2		;Yes -- dispatch to handler

		; --- Event dispatch table ---

		B	dbox__hint		;Hint for the hint bar
		MOVS	PC,R14			;Null event
		B	dbox__redraw		;Redraw window request
		B	dbox__open		;Open window request
		B	dbox__close		;Close window request
		B	dbox__enterLeave	;Pointer leaving window
		B	dbox__enterLeave	;Pointer entering window
		B	dbox__mouse		;Mouse clicked
		MOVS	PC,R14			;Drag event
		B	dbox__keyPress		;Key pressed

		; --- Handle a message ---

00dbox__events	CMP	R0,#17			;User message
		CMPNE	R0,#18			;Rubber message (bouncy!)
		MOVNES	PC,R14			;No -- return unhandled
		B	dbox__message		;Handle the message event

; --- dbox__dispatch ---
;
; On entry:	R0 == the (dbox-style) event code to dispatch
;		R1-R7 == any additional arguments that want passing along
;		R10 == the dialogue box to send the event to
;
; On exit:	CS or CC from the event handler
;
; Use:		Dispatches an event to the event handler associated with the
;		dialogue box, and returns its response.

dbox__dispatch	ROUT

		STMFD	R13!,{R8-R10,R12,R14}	;Save lots of registers
		MOV	R9,R10			;Pass dialogue handle in R9
		ADDS	R0,R0,#0		;Clear the carry flag
		LDMIB	R10,{R8,R10,R12}	;Get the event handler stuff
		TEQ	R8,#0			;Is there an event handler?
		MOVNE	R14,PC			;Set up return address
		MOVNE	PC,R8			;Call the event handler
		LDMFD	R13!,{R8-R10,R12,R14}	;Restore the registers
		ORRCSS	PC,R14,#C_flag		;Return CS if it returned CS
		BICCCS	PC,R14,#C_flag		;Return CC if it returned CC

		LTORG

; --- dbox__checkIcon ---
;
; On entry:	R1 == icon handle
;		R10 == dialogue box handle
;
; On exit:	R1 == icon handle or -1 if it was shaded
;
; Use:		Translates an icon handle to the window background if it
;		is shaded, for passing to event handlers.

dbox__checkIcon	ROUT

		STMFD	R13!,{R0,R14}		;Save some registers
		MOV	R0,R1			;Move icon handle along
		BL	dbox__icon		;Find the icon definition
		LDR	R14,[R0,#16]		;Load the icon flags
		TST	R14,#&00400000		;Is the icon shaded?
		MOVNE	R1,#-1			;Yes -- return background
		STR	R1,dbox__eventIcon	;Store in workspace
		LDMFD	R13!,{R0,PC}^		;Return to caller

		LTORG

; --- dbox__hint ---
;
; On entry:	R0 == -1
;		R1 == pointer to hint event block
;
; On exit:	C set if handled
;
; Use:		Sends a hint event to the dbox handler

dbox__hint	ROUT

		STMFD	R13!,{R0-R2,R14}	;Save some registers
		MOV	R0,#dbEvent_hint	;The event code
		ADD	R2,R1,#4		;Point to the string
		BL	dbox__dispatch		;Send it to the handler
		LDMFD	R13!,{R0-R2,PC}		;Return with its flags

		LTORG

; --- dbox__redraw ---
;
; On entry:	R0 == 1
;		R1 == pointer to window handle
;
; On exit:	C set
;
; Use:		Redraws a window using Sculptrix

dbox__redraw	ROUT

		STMFD	R13!,{R0,R2,R3,R14}	;Save some registers

		; --- Start the redraw operation ---

		SWI	Wimp_RedrawWindow	;Start the redraw
		CMP	R0,#0			;Is it over already?
		BEQ	%10dbox__redraw		;Yes -- skip to the end

		; --- Set up Sculptrix's sprite area ---

		LDR	R0,[R10,#dbox__defn]	;Find the window definition
		LDR	R0,[R0,#64]		;Load the sprite area pointer
		SWI	XSculptrix_SetSpriteArea ;Set up the sprite area

		; --- Do any bits that need doing ---

00dbox__redraw	LDR	R2,[R1,#4]		;Get the window left position
		ADD	R0,R1,#16		;Point to the top position
		LDMIA	R0,{R0,R3,R14}		;Load top, and scroll posns
		SUB	R2,R2,R3		;Convert to find origin x
		SUB	R3,R0,R14		;Convert to find origin y
		MOV	R0,#dbEvent_redraw	;Give user a redraw event
		BL	dbox__dispatch		;Send it to the handler
		BCS	%01dbox__redraw		;If it claimed it, skip ahead

		LDR	R0,[R10,#dbox__title]	;Get the embedded title icon
		CMP	R0,#-1			;Has it been defined?
		MOVNE	R0,R10			;Give it the dialogue box
		BLNE	dbox_renderTitle	;Yes -- render it nicely

		SWI	XSculptrix_RedrawWindow	;Get Sculptrix to do its bit

01dbox__redraw	SWI	Wimp_GetRectangle	;Get the next rectangle
		CMP	R0,#0			;Is this the end yet?
		BNE	%00dbox__redraw		;No -- do the rest

		; --- That's it, then ---

10dbox__redraw	LDMFD	R13!,{R0,R2,R3,R14}	;Unstack all the registers
		ORRS	PC,R14,#C_flag		;Set carry and return

		LTORG

; --- dbox__open ---
;
; On entry:	R0 == 2
;		R1 == pointer to window open block
;
; On exit:	C set
;
; Use:		This just opens the window.  Later, it may do clever things
;		with panes.

dbox__open	SWI	Wimp_OpenWindow		;Open the window
		ORRS	PC,R14,#C_flag		;Set carry and return

; --- dbox__close ---
;
; On entry:	R0 == 3
;		R1 == pointer to the window handle
;
; On exit:	C set
;
; Use:		Passes a close event to the user dialogue box handler.

dbox__close	STMFD	R13!,{R0,R14}		;Save some registers
		MOV	R0,#dbEvent_close	;The close event code
		BL	dbox__dispatch		;Pass it to the handler
		LDMFD	R13!,{R0,R14}		;Unstack all the registers
		ORRS	PC,R14,#C_flag		;Set carry and return

; --- dbox__mouse ---
;
; On entry:	R0 == 6
;		R1 == pointer to mouse status block
;
; On exit:	C set if we understood the event, C clear otherwise
;
; Use:		Passes a click event to the dbox event handler.

dbox__mouse	ROUT

		STMFD	R13!,{R0-R2,R9,R14}	;Save some registers
		MOV	R9,R1			;Keep the event pointer
		LDR	R1,[R9,#8]		;Get the button status
		TST	R1,#&5			;Is it Select or Adjust?
		BNE	%10dbox__mouse		;Yes -- handle it nicely
		TST	R1,#&50			;Is it a drag event?
		BNE	%20dbox__mouse		;Yes -- handle it nicely
		TST	R1,#&2			;Is it a menu click?
		LDMEQFD	R13!,{R0-R2,R9,PC}^	;No -- we're clueless then

		; --- The user clicked Menu ---

		LDR	R1,[R9,#16]		;Get the icon handle out
		MOV	R0,#dbEvent_menu	;Give it a menu click
		BL	dbox__checkIcon		;Handle icon shadedness
		BL	dbox__dispatch		;Give it to the user
		B	%80dbox__mouse		;And return C set

		; --- The user clicked Select or Adjust ---

10dbox__mouse	LDR	R1,[R9,#16]		;Get the icon handle out
		BL	dbox__checkIcon		;Handle icon shadedness
		MOV	R0,R1			;Return icon number as event
		LDR	R1,[R9,#8]		;Load the button state again
		BL	dbox__dispatch		;Dispatch the event out
		BCS	%80dbox__mouse		;If handled, skip this bit

		MOV	R1,R0			;Get the icon handle in R1
		MOV	R0,R10			;And dialogue handle in R0
		BL	dbox_radio		;Handle magic radio buttons

		LDR	R0,[R10,#dbox__flags]	;Get this dialogue's flags
		TST	R0,#dbFlag__drag	;Is the move on drag bit on?
		BEQ	%80dbox__mouse		;No -- skip this bit out

		SUB	R13,R13,#56		;Make a drag info block
		LDR	R0,[R10,#dbox__window]	;Get the window handle
		STR	R0,[R13,#0]		;Store the window handle
		MOV	R0,#1			;Move the window
		STR	R0,[R13,#4]		;Store the drag type
		MOV	R1,R13			;Point to the block
		SWI	Wimp_DragBox		;Start the window moving
		ADD	R13,R13,#56		;Reclaim the stack space
		B	%80dbox__mouse		;Skip ahead to claim event

		; --- The user dragged an icon ---

20dbox__mouse	LDR	R1,[R9,#16]		;Get the icon handle out
		BL	dbox__checkIcon		;Handle shadiness nicely
		MOV	R2,R1			;Move handle to right place
		LDR	R1,[R9,#8]		;Load button status again
		MOV	R0,#dbEvent_drag	;Give handler a drag event
		BL	dbox__dispatch		;And pass it to the handler
		B	%80dbox__mouse		;And claim the event

		; --- Finish everything off nicely ---

80dbox__mouse	LDMFD	R13!,{R0-R2,R9,R14}	;Restore the registers
		ORRS	PC,R14,#C_flag		;Claim the event nicely

		LTORG

; --- dbox__enterLeave ---
;
; On entry:	R0 == 4 for leaving, 5 for entering
;
; On exit:	--
;
; Use:		Informs dialogue handlers that pointer has entered or left
;		a window.

dbox__enterLeave ROUT

		STMFD	R13!,{R0,R14}		;Save some registers
		ADD	R0,R0,#dbEvent_leave-4	;Convert to appropriate event
		BL	dbox__dispatch		;Send it to the handler
		LDMFD	R13!,{R0,PC}^		;And return to caller

		LTORG

; --- dbox__keyPress ---
;
; On entry:	R0 == 8
;		R1 == pointer to caret block
;
; On exit:	C clear
;
; Use:		Handles key events for a dialogue box

dbox__keyPress	ROUT

		STMFD	R13!,{R0-R3,R14}	;Save some registers

		; --- Send the event to the user ---

		LDR	R2,[R1,#4]		;Get the icon handle
		STR	R2,dbox__eventIcon	;Store it in workspace
		LDR	R0,[R1,#24]		;Get the key code
		BL	akbd_translate		;Mangle for extended keyset
		MOV	R1,R0			;Move into right register
		MOV	R0,#dbEvent_key		;Key event code
		BL	dbox__dispatch		;Send it to the user
		BCS	%50dbox__keyPress	;If processed, skip ahead

		; --- Now see if it's one of ours ---

		CMP	R1,#&100		;Is it an extended code?
		BGE	%20dbox__keyPress	;Yes -- skip forward

		CMP	R1,#key_Return		;Is it a return?
		MOVEQ	R0,#dbEvent_OK		;Yes -- give out an OK event
		BEQ	%10dbox__keyPress	;Send it on its way
		CMP	R1,#key_Esc		;Or maybe an escape
		MOVEQ	R0,#dbEvent_cancel	;Yes -- give a Cancel event
		BEQ	%10dbox__keyPress	;Send it on its way

00		LDMFD	R13!,{R0-R3,PC}^	;Forget it -- don't know

		; --- Send a key event on ---

10		MOV	R1,#4			;Pretend Select was pressed
		BL	dbox__dispatch		;Send it to the client
		B	%50dbox__keyPress	;Now we've done the deed...

11		MOV	R1,#1			;Pretend Adjust was pressed
		BL	dbox__dispatch		;Send it to the client
		B	%50dbox__keyPress	;Now we've done the deed...

		; --- Handle an extended key ---

20		AND	R2,R1,#&FF		;Leave the bottom byte

		; --- Straight cursor keys ---

		MOV	R0,#0

		CMP	R2,#key_kEnter-256
		MOVEQ	R0,#dbEvent_OK
		BEQ	%10dbox__keyPress

		CMP	R2,#key_sReturn-256
		CMPNE	R2,#key_skEnter-256
		MOVEQ	R0,#dbEvent_OK
		BEQ	%11dbox__keyPress

		CMP	R2,#key_sEsc-256
		MOVEQ	R0,#dbEvent_cancel
		BEQ	%11dbox__keyPress

		CMP	R2,#key_Up-256
		CMPNE	R2,#key_sTab-256
		MOVEQ	R1,#-1
		BEQ	%40dbox__keyPress

		CMP	R2,#key_Down-256
		CMPNE	R2,#key_Tab-256
		MOVEQ	R1,#+1
		BEQ	%40dbox__keyPress

		; --- Control cursor keys ---

		MOV	R0,#1

		CMP	R2,#key_cUp-256
		MOVEQ	R1,#+1
		BEQ	%40dbox__keyPress

		; --- Cursor up ---

		CMP	R2,#key_cDown-256
		MOVEQ	R1,#-1
		BEQ	%40dbox__keyPress

		; --- Nothing worth knowing about ---

		B	%00dbox__keyPress

		; --- Actually do a cursor move ---

40		BL	dbox__moveCaret		;Do the cursor move

		; --- Return and claim the keypress ---

50		LDMFD	R13!,{R0-R3,R14}
		ORRS	PC,R14,#C_flag

		LTORG

; --- dbox__message ---
;
; On entry:	R0 == 17 or 18
;		R1 == pointer to message data
;
; On exit:	C set if the event was handled, or clear otherwise
;
; Use:		Handles messages sent to dialogue boxes.

dbox__message	ROUT

		STMFD	R13!,{R0-R4,R9,R14}	;Save some registers
		MOV	R9,R1			;Point to the event block
		LDR	R14,[R9,#16]		;Get the message type number
		CMP	R14,#1			;Is it a save message?
		CMPNE	R14,#3			;Or a load message?
		BEQ	%10dbox__message	;Yes -- handle them the same
		MOV	R0,#&500		;&502 is a help request
		ORR	R0,R0,#&002		;Build the full number
		CMP	R14,R0			;Is it a help request?
		LDMNEFD	R13!,{R0-R4,R9,PC}^	;No -- we don't understand

		; --- Handle help requests for the dbox ---

		LDR	R1,[R9,#36]		;Obtain the icon handle
		BL	dbox__checkIcon		;Handle icon shadiness
		MOV	R0,#dbEvent_help	;Pass a help request on
		BL	dbox__dispatch		;Send it to the client
		B	%80dbox__message	;Skip on and claim the event

		; --- Handle save and load events ---

10dbox__message	CMP	R14,#1			;Is it a save message?
		MOVEQ	R0,#dbEvent_save	;Yes -- give a save event
		MOVNE	R0,#dbEvent_load	;No -- give a load event
		LDR	R1,[R9,#24]		;Get the icon handle
		BL	dbox__checkIcon		;Handle icon shadiness
		LDR	R2,[R9,#40]		;Get filetype in R2
		ADD	R3,R9,#44		;Point to filename with R3
		LDR	R4,[R9,#36]		;Estimated size in R4
		BL	dbox__dispatch		;Send the message on
		B	%80dbox__message	;Skip on and claim the event

		; --- We did something, so claim event ---

80dbox__message	LDMFD	R13!,{R0-R4,R9,R14}	;Restore all the registers
		ORRS	PC,R14,#C_flag		;Return, claiming the event

		LTORG

;----- Locating icons -------------------------------------------------------

; --- dbox__find ---
;
; On entry:	R0 == icon number to start from or -1
;		R1 == AND mask for flags
;		R2 == flags word to match
;		R3 == direction to scan in (either +1 or -1 unless you're
;		      very odd)
;		R10 == dialogue box handle
;
; On exit:	R0 == icon number of found icon or -1
;		Other registers preserved
;
; Use:		Locates an icon within a window with flags that match the
;		ones given.  Note that icon definitions within the cached
;		window definition are scanned, not icons in their actual
;		current state.
;
;		Searching from icon `-1' means to start from one end and
;		keep looking until you've gone through all of them.
;		Otherwise, the scan starts from the icon *after* the one
;		specified in R0 on entry.
;
;		The return value is the number of the first icon that
;		matched the specification, or -1 if none of them matched.

dbox__find	ROUT

		STMFD	R13!,{R4-R6,R14}	;Save some registers

		; --- Find the cached window defintion ---

		LDR	R4,[R10,#dbox__defn]	;Locate the definition

		; --- Work out a sensible scanning start position ---

		CMP	R0,#-1			;Extremity requested?
		ADDNE	R0,R0,R3		;No -- skip over start icon
		BNE	%00dbox__find		;And skip past this bit
		CMP	R3,#0			;Is the increment positive?
		MOVGT	R0,#0			;Yes -- start from 0
		LDRLT	R0,[R4,#84]		;No -- load the icon count
		SUBLT	R0,R0,#1		;And bump down -- zero index

		; --- Now work out when to stop scanning ---

00dbox__find	CMP	R3,#0			;What's the increment again?
		BEQ	%02dbox__find		;If it's silly, find nothing
		LDRGT	R5,[R4,#84]		;Positive -- stop at the
		SUBGT	R5,R5,#1		;...number of icons -1

		; --- A few other pre-scan bits ---

		AND	R2,R2,R1		;Make sure flags aren't silly
		ADD	R6,R4,#88		;Point to icon number 0
		ADD	R6,R6,R0,LSL #5		;Point to the right icon

		; --- The main scanning loop ---
		;
		; The comparison at the end is slightly tricky.  It works
		; on the basis that if R3>0, the condition is that R0>R5,
		; and if R3<0, the condition is that R0<0.  Each of these
		; double-barrelled conditions can be done in two ARM
		; instructions, and both together, complete with branches
		; can be done in 6.
		;
		; Rather oddly, we start with the termination condition.

01dbox__find	CMP	R3,#0			;What's the increment like?
		CMPLT	R0,#0			;Check not gone too low
		BLT	%02dbox__find		;Yes -- exit the loop
		CMP	R3,#0			;Check increment again
		CMPGT	R0,R5			;Check not gone too high
		BGT	%02dbox__find		;Yes -- exit the loop

		; --- Now see if we got a match ---

		LDR	R14,[R6,#16]		;Get icon flags for this one
		AND	R14,R14,R1		;Apply the AND mask to them
		CMP	R14,R2			;Is this a match?
		LDMEQFD	R13!,{R4-R6,PC}^	;Yes -- return to caller

		; --- Set up for the next one ---

		ADD	R0,R0,R3		;Move the icon number on
		ADD	R6,R6,R3,LSL #5		;And bump icon pointer too
		B	%01dbox__find		;Jump back to the loop start

		; --- We failed to find it -- return -1 ---

02dbox__find	MOV	R0,#-1			;Return funny failure value
		LDMFD	R13!,{R4-R6,PC}^	;Return to caller

		LTORG

; --- dbox__icon ---
;
; On entry:	R0 == icon number wanted
;		R10 == dialogue box block pointer
;
; On exit:	R0 == pointer to numbered icon's definition
;
; Use:		Locates an icon definition given its number

dbox__icon	STMFD	R13!,{R14}		;Save link register a bit
		LDR	R14,[R10,#dbox__defn]	;Find window definition
		ADD	R14,R14,#88		;Point to the first icon
		ADD	R0,R14,R0,LSL #5	;Add R0*32 to point to icon
		LDMFD	R13!,{PC}^		;Return to caller nicely

;----- Main initialisation --------------------------------------------------

; --- dbox_init ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Initialises the dbox system.

		EXPORT	dbox_init
dbox_init	ROUT

		STMFD	R13!,{R12,R14}		;Save a load of registers
		WSPACE	dbox__wSpace		;Find my workspace

		; --- Make sure I'm not running yet ---

		LDR	R14,dbox__wFlags	;Get hold of my flags word
		TST	R14,#dbFlag__inited	;Am I running yet?
		LDMNEFD	R13!,{R12,PC}^		;Yes -- return immediately

		; --- Set up the flags nicely ---

		MOV	R14,#dbFlag__inited	;I am initialised now
		STR	R14,dbox__wFlags	;Save my flags back again
		MOV	R14,#0			;Zero some workspace bits
		STR	R14,dbox__clickList	;Nothing on the click list
		BL	win_init		;Make sure win's awake
		BL	transWin_init		;And also for transWin
		LDMFD	R13!,{R12,PC}^		;Return to caller

		LTORG

dbox__wSpace	DCD	0

;----- Opening and closing dialogue boxes -----------------------------------

; --- dbox_open ---
;
; On entry:	R0 == dialogue box handle
;		R1 == how to open the dialogue box
;		Other registers depend on R1, and are described at the end
;		of this header file
;
; On exit:	--
;
; Use:		Displays the dialogue box on the screen in the given manner.

		EXPORT	dbox_open
dbox_open	ROUT

		STMFD	R13!,{R0-R6,R10,R12,R14}
		WSPACE	dbox__wSpace		;Locate my workspace
		MOV	R10,R0			;Move the dbox handle away

		; --- Is this a submenu request? ---

		ADDS	R0,R0,#0		;Clear the C flag
		TST	R1,#dbOpen_nonSub	;Do we ignore this?
		BLEQ	transWin_subWaiting	;No -- waiting for a submenu?
		BCS	%60dbox_open		;Yes -- open as a submenu

		; --- Now work out how to open it ---

		LDR	R6,[R10,#dbox__flags]	;Get the dialogue's flags
		TST	R1,#dbOpen_persist	;Is this a persistent dbox?
		BICEQ	R6,R6,#dbFlag__static	;No -- clear static flag
		ORRNE	R6,R6,#dbFlag__static	;Yes -- set static flag
		MOV	R4,R1			;Look after open style

		; --- Read the dialogue's position ---

		SUB	R13,R13,#36		;Enough for a window block
		LDR	R0,[R10,#dbox__window]	;Get the window handle
		STR	R0,[R13,#0]		;Store it in the block
		MOV	R1,R13			;Point to the window handle
		SWI	Wimp_GetWindowState	;Read in the information

		; --- Move the dialogue box to the right position ---

		BIC	R0,R4,#dbOpen_persist + dbOpen_nonSub
		BL	winUtils_setPosition	;Position the window nicely
		TST	R6,#dbFlag__static	;Is it static?
		BEQ	%40dbox_open		;No -- skip ahead a bit

		; --- Open a persistent dialogue box ---

		SWI	Wimp_OpenWindow		;Open the window
		ADD	R13,R13,#36		;Reclaim the stack space

		; --- If the window was already open, quit now ---

		TST	R6,#dbFlag__open	;Is the dialogue box open
		BNE	%80dbox_open		;Yes -- skip past this bit

		; --- Now find out if there's a caret to handle ---

		MOV	R0,#-1			;Start searching from start
		MOV	R1,#&0000E000		;Find all Writable icons
		MOV	R2,#&0000E000		;Only check button type bits
		MOV	R3,#+1			;Search forwards
		BL	dbox__find		;Find the icon
		CMP	R0,#-1			;Is there a writable icon?
		BICEQ	R6,R6,#dbFlag__rCaret	;Don't have to restore caret
		BEQ	%10dbox_open		;No -- skip ahead

		; --- Read the old caret position ---

		ADD	R1,R10,#dbox__oldCaret	;Point to old caret block
		SWI	Wimp_GetCaretPosition	;Read the current position
		LDR	R0,[R10,#dbox__window]	;Get the dialogue window
		MOV	R1,#-1			;In no particular icon
		MOV	R2,#&ff000000		;Quite a long way away
		ORR	R2,R2,#&00ff0000
		MOV	R3,#0			;Doesn't really matter
		MOV	R4,#&02000000		;Hide caret, make it small
		MOV	R5,#-1			;No index into icon, please
		SWI	Wimp_SetCaretPosition	;Set the caret's position
		ORR	R6,R6,#dbFlag__rCaret	;Remember to restore caret

		; --- That's it, so finish things off ---

10dbox_open	B	%80dbox_open		;Perform wrapping-up actions

		; --- Open as a transient menu ---

40dbox_open	LDR 	R1,[R10,#dbox__window]	;Get the window handle ready
		SWI	Wimp_CreateMenu		;Create it as a menu :-/
		BIC	R6,R6,#dbFlag__rCaret	;Don't restore the caret
		ADD	R13,R13,#36		;Reclaim the stack we used
		MOV	R0,R1			;Get the window handle again
		BL	transWin_register	;This is transient window
		B	%80dbox_open		;Perform wrapping-up actions

		; --- Open in the correct submenu position ---

60dbox_open	LDR	R0,[R10,#dbox__window]	;Load the window handle
		BL	transWin_openSub	;And display as submenu
		LDR	R6,[R10,#dbox__flags]	;Read the dialogue box flags
		BIC	R6,R6,#dbFlag__static :OR: dbFlag__rCaret

		; --- Wrap everything up now ---

80dbox_open	ORR	R6,R6,#dbFlag__open	;The window is at last open
		STR	R6,[R10,#dbox__flags]	;Store the flags away now
		LDMFD	R13!,{R0-R6,R10,R12,PC}^

		LTORG

; --- dbox_close ---
;
; On entry:	R0 == dialogue box handle
;
; On exit:	--
;
; Use:		Closes a dialogue box, by clearing the current menu if
;		necessary.

		EXPORT	dbox_close
dbox_close	ROUT

		STMFD	R13!,{R0-R6,R10,R12,R14} ;Save some registers away
		WSPACE	dbox__wSpace		;Locate my workspace
		MOV	R10,R0			;Move dbox handle away

		; --- First things first -- check it's open ---

		LDR	R6,[R10,#dbox__flags]	;Get the dialogue's flags
		TST	R6,#dbFlag__open	;Is the open flag on?
		BEQ	%80dbox_close		;No -- skip forward

		; --- Now restore the caret if needs be ---
		;
		; Try not to be overly upset if we can't put the caret back.
		; After all, the window may have closed by now.  An X SWI
		; is called for, and we ignore V on exit.

		TST	R6,#dbFlag__rCaret	;Does caret need restoring?
		BEQ	%00dbox_close		;No -- skip forwards
		ADD	R0,R10,#dbox__oldCaret	;Point to old caret block
		LDMIA	R0,{R0-R5}		;Load the old caret state
		SWI	XWimp_SetCaretPosition	;And try to put it back

		; --- Now handle transientness properly ---

00dbox_close	TST	R6,#dbFlag__static	;Is this a static dialogue?
		LDREQ	R0,[R10,#dbox__window]	;Yes -- find the window
		BLEQ	transWin_close		;And close it
		ADDNE	R1,R10,#dbox__window	;Point to the window handle
		SWINE	Wimp_CloseWindow	;Close the window now

		BIC	R6,R6,#dbFlag__open :OR: dbFlag__rCaret
		STR	R6,[R10,#dbox__flags]	;Store flags away again

80dbox_close	LDMFD	R13!,{R0-R6,R10,R12,PC}^ ;Return to caller

		LTORG

; --- dbox_writePos ---
;
; On entry:	R0 == dialogue box handle
;
; On exit:	--
;
; Use:		Saves the dialogue's current position so that it will be
;		opened here the next time it is created.  If the dialogue
;		box was created from a template, the template is updated.
;		Otherwise, the new state is written back to the definition
;		supplied to dbox_fromDefn.

		EXPORT	dbox_writePos
dbox_writePos	ROUT

		STMFD	R13!,{R0-R5,R10,R14}	;Save a load of registers
		MOV	R10,R0			;Keep the dialogue handle
		SUB	R13,R13,#36		;Make space on the stack
		LDR	R14,[R10,#dbox__window]	;Get the dialogue's window
		STR	R14,[R13,#0]		;Save in the block
		MOV	R1,R13			;Point to the block
		SWI	Wimp_GetWindowState	;Get the window's position
		LDMIB	R13,{R0-R5}		;Load pos and scroll settings
		LDR	R14,[R10,#dbox__template] ;Find the template address
		CMP	R14,#0			;Is it actually there?
		CMPNE	R14,#1			;Check for embedded templates
		LDREQ	R14,[R10,#dbox__defn]	;No -- just use definition
		STMIA	R14,{R0-R5}		;Yes -- save them for later
		ADD	R13,R13,#36		;Reclaim the used stack space
		LDMFD	R13!,{R0-R5,R10,PC}^	;Return to caller

		LTORG

;----- Caret handling functions ---------------------------------------------

; --- dbox__viewIcon ---
;
; On entry:	R0 == an icon number
;		R10 == dialogue box handle
;
; On exit:	--
;
; Use:		Scrolls the given dialogue box so that the specified icon
;		is visible.  The icon is assumed to be in the same position
;		as it was when it was created.
;
;		This is translated fairly literally from the STEEL code
;		in dbox__nextWritable.

dbox__viewIcon	ROUT

		STMFD	R13!,{R0-R9,R14}	;Save a load of registers

		; --- Locate the icon definition ---

		BL	dbox__icon		;Find the icon position
		MOV	R9,R0			;Keep a pointer to it

		; --- Find the window position ---

		SUB	R13,R13,#36		;Make space for a window def
		LDR	R14,[R10,#dbox__window]	;Find the dbox's window hnd
		STR	R14,[R13,#0]		;Store it in the block
		MOV	R1,R13			;Point to the block
		SWI	Wimp_GetWindowState	;Find the window information

		; --- Now read the window scroll positions ---

		LDMIB	R13,{R0-R5}		;Load window visible coords

		SUB	R0,R2,R0		;R0 == window width
		SUB	R1,R3,R1		;R1 == window height
		ADD	R2,R4,R0		;R2 == window right hand side
		SUB	R3,R5,R1		;R3 == window bottom edge
						;R4 == window left hand side
						;R5 == window top edge

		LDMIA	R9,{R6-R8,R14}		;Load icon coordinates nicely

		SUB	R6,R6,#16		;Add a bit of extra around
		SUB	R7,R7,#16
		ADD	R8,R8,#16
		ADD	R14,R14,#16

		; --- Bodge the scroll positions until icon is visible ---
		;
		; This section is fairly self-explanatory, and the comments
		; are very dull.

		CMP	R7,R3
		ADDLT	R5,R7,R1
		CMP	R14,R5
		MOVGT	R5,R14
		CMP	R6,R4
		MOVLT	R4,R6
		CMP	R8,R2
		SUBGT	R4,R8,R0

		; --- Now store the scroll offsets back and reopen ---

		ADD	R1,R13,#20		;Point to scroll offsets
		STMIA	R1,{R4,R5}		;Store them back in the block
		MOV	R1,R13			;Point to the block
		SWI	Wimp_OpenWindow		;Now open the window nicely

		; --- Reclaim the stack and return ---

		ADD	R13,R13,#36
		LDMFD	R13!,{R0-R9,PC}^	;Return to caller

		LTORG

; --- dbox__moveCaret ---
;
; On entry:	R0 == 0 to move relative to current input focus
;		      1 to move absolute (for ctrl cursor keys)
;		R1 == direction to move in (+1 or -1, if you've any sense)
;		R10 == dialogue box handle
;
; On exit:	--
;
; Use:		Moves the caret between writable icons, responding to cursor
;		key presses.

dbox__moveCaret	ROUT

		STMFD	R13!,{R0-R5,R14}	;Save a few registers

		; --- Find out where the cursor is ---

		SUB	R13,R13,#24		;Make way for a caret block
		MOV	R1,R13			;Point to it
		SWI	Wimp_GetCaretPosition	;Find the caret nicely

		; --- Check this is the right window ---

		LDMIA	R13,{R0,R5}		;Get the input focus window
		LDR	R14,[R10,#dbox__window]	;Get dialogue box window
		ADD	R13,R13,#24		;Reclaim that stack space
		CMP	R0,R14			;Do they match nicely?
		LDMNEFD	R13!,{R0-R5,PC}^	;No -- return to caller

		; --- Now set up a search for the icon ---

		LDMIA	R13,{R0,R3}		;Get the stacked start pos
		CMP	R0,#0			;Is it a zero?
		MOVNE	R0,#-1			;No -- start from one end
		MOVEQ	R0,R5			;Yes -- start from current

		; --- Load the icon flags to search for ---

		MOV	R2,#&0000E000		;Find writable icons
		ORR	R1,R2,#&00400000	;Also check shaded bit
		BL	dbox__find		;Find the icon nicely
		CMP	R0,#-1			;Did it find one?
		BLEQ	dbox__find		;No -- search from one end

		; --- Now it's come up with the goods ---

		CMP	R0,#-1			;Did it fail this time?
		CMPNE	R0,R5			;Or just come back again?
		LDMEQFD	R13!,{R0-R5,PC}^	;Yes -- nothing doing then

		; --- Scroll to make icon visible ---

		BL	dbox__viewIcon		;Scroll the window nicely

		; --- Set the caret position nicely ---

		MOV	R1,R0			;Icon number to R1
		BL	dbox__fieldLen		;Find the string length
		MOV	R5,R0			;This is icon text index
		MOV	R4,#-1			;Calculate things for me
		LDR	R0,[R10,#dbox__window]	;Get the window handle
		SWI	Wimp_SetCaretPosition	;Move the caret nicely now

		LDMFD	R13!,{R0-R5,PC}^	;Return to caller at last

		LTORG

;----- Selecting and shading icons ------------------------------------------

; --- dbox_select ---
;
; On entry:	R0 == dialogue box handle
;		R1 == icon number
;		R2 == 0 to deselect the icon, 1 to select it, 2 to toggle
;		      its current selected state
;
; On exit:	--
;
; Use:		Selects or deselects the specified icon in the Acorn sense
;		(i.e. by flipping its selected bit).  The state is only
;		changed if required, to reduce flicker.

		EXPORT	dbox_select
dbox_select	ROUT

		STMFD	R13!,{R0-R2,R14}	;Save some registers away

		; --- Find the old state ---

		SUB	R13,R13,#40		;Make space for an icon block
		LDR	R0,[R0,#dbox__window]	;Get the window handle
		STMIA	R13,{R0,R1}		;Save the handles away
		MOV	R1,R13			;Point to the block
		SWI	Wimp_GetIconState	;Find out about the icon

		; --- Find out the current selection state ---

		LDR	R14,[R13,#24]		;Load the flags word
		AND	R14,R14,#&00200000	;Clear all but the select bit
		CMP	R2,#1			;Are we to select the icon?
		MOVEQ	R2,#&00200000		;Yes -- set the select bit
		CMP	R2,#2			;Are we to toggle it?
		EOREQ	R2,R14,#&00200000	;Yes -- toggle it then

		; --- Make sure we need to do something ---

		CMP	R2,R14			;Are the states the same?
		ADDEQ	R13,R13,#40		;Yes -- restore the stack
		LDMEQFD	R13!,{R0-R2,PC}^	;And return right now

		; --- Now change the icon state ---

		ADD	R0,R13,#8		;Point to the flags masks
		MOV	R14,#&00200000		;Clear only the selected bit
		STMIA	R0,{R2,R14}		;Save the masks in the block
		SWI	Wimp_SetIconState	;Set the state nicely

		ADD	R13,R13,#40		;Restore the stack nicely
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

		LTORG

; --- dbox_shade ---
;
; On entry:	R0 == dialogue box handle
;		R1 == icon number
;		R2 == 0 to unshade the icon, 1 to shade it, 2 to toggle its
;		      current shaded state
;
; On exit:	--
;
; Use:		Makes the icon look dimmer, to indicate that it is not
;		available.  It uses its own shading algorithms, rather than
;		the WindowManager's, so there are some things you must watch
;		out for:
;
;		* Don't use any other method of shading icons
;
;		* Don't assume that a shaded icon isn't going to give you
;		  events.  At the user level, this should have been tidied
;		  up, but at the Sapphire level, it's still a problem.
;		  There is a routine in winUtils which will tell you if an
;		  icon is shaded.
;
;		This routine has been written so that it only flickers icons
;		when they actually need it.

		EXPORT	dbox_shade
dbox_shade	ROUT

		STMFD	R13!,{R0-R6,R10,R14}	;Save a load of registers

		; --- Make sure we need to do something ---

		MOV	R10,R0			;Look after the dbox handle
		MOV	R0,R1			;Get the original icon handle
		BL	dbox__icon		;Find my cached icon defn
		MOV	R4,R0			;Look after this pointer
		LDR	R6,[R4,#16]		;Load the icon's flags
		AND	R5,R6,#&00400000	;Leave only the selected bit

		; --- Work out what needs to be done ---

		CMP	R2,#1			;Do we have to shade it?
		MOVEQ	R2,#&00400000		;Yes -- set the bit
		CMP	R2,#2			;Do we have to toggle it?
		EOREQ	R2,R5,#&00400000	;Yes -- get the toggled state

		; --- Now quit if there's nothing to do ---

		CMP	R2,R5			;Are they the same now?
		LDMEQFD	R13!,{R0-R6,R10,PC}^	;Yes -- return right now

		; --- Find the old state from the icon ---

		LDR	R0,[R10,#dbox__window]	;Get the window handle
		SUB	R13,R13,#40		;Make way for an icon block
		STMIA	R13,{R0,R1}		;Save window and icon handles
		MOV	R1,R13			;Point to the block
		SWI	Wimp_GetIconState	;Get the icon information
		LDR	R5,[R13,#24]		;Get the current icon flags

		; --- Now process the cached flags nicely ---
		;
		; We can just flip the bit now, because we know it must be
		; different to its old state.

		EOR	R6,R6,#&00400000	;Toggle the flag
		STR	R6,[R4,#16]		;Store it back in the block

		; --- Now work out exactly what we have to do ---

		TST	R6,#&00400000		;Are we meant to be shading?
		BEQ	%50dbox_shade		;No -- unshade nicely

		; --- Lots of messing about with bitmasks ---
		;
		; We need to change the icon colours, the button type and
		; the ESG number for text icons, and the shaded bit for
		; sprite icons.  If there's a sprite, or nothing at all, then
		; we set the shaded bit.  If there's text and a sprite, then
		; we /don't/ do the text hacking if anti-aliased fonts are
		; being used, since everything looks nasty.

		MOV	R0,#8			;Read the font handle
		SWI	XWimp_ReadSysInfo	;Read the handle then
		MOVVS	R0,#0			;Unknown -- not supported

		AND	R14,R5,#3		;Get the contents bits
		TST	R14,#2			;Do we have a sprite?
		CMPNE	R0,#0			;And is there a font?
		TSTEQ	R5,#&40			;Or is the icon anti-aliased?
		BICNE	R14,R14,#1		;Yes -- clear text bit then

		CMP	R14,#1			;Is it text only?
		ORRNE	R5,R5,#&00400000	;No -- set the shaded bit
		TST	R14,#1			;Does it contain text?
		BICNE	R5,R5,#&0f100000	;Clear foreg colour and ESG 5
		BICNE	R5,R5,#&000ff000	;Clear ESG and button type
		ORRNE	R5,R5,#&02100000	;Set foreg and ESG bit 5
		ORRNE	R5,R5,#&000f0000	;Set ESG to 31, leave btype

		MOV	R14,#-1			;Clear all the flags bits
		ADD	R0,R13,#8		;Point to flags masks
		STMIA	R0,{R5,R14}		;Store them in the block
		MOV	R1,R13			;Point to the block again
		SWI	Wimp_SetIconState	;And `shade' the icon

		; --- Now make sure the caret's not in it ---

		LDMIA	R1,{R2,R3}		;Get the window and icon
		SWI	Wimp_GetCaretPosition	;Find where the caret is
		LDMIA	R1,{R4,R5}		;Get the focus window and icn
		CMP	R2,R4			;Check the windows match
		CMPEQ	R3,R5			;And check the icons match
		BNE	%80dbox_shade		;If not, skip ahead a bit

		; --- Now kick the caret into cyberspace ---

		LDMIA	R1,{R0-R5}		;Load the caret registers
		MOV	R1,#-1			;Kick caret out of icon
		MOV	R2,#&ff000000		;Quite a long way away
		ORR	R2,R2,#&00ff0000
		SWI	Wimp_SetCaretPosition	;Set the new caret position
		B	%80dbox_shade		;Tidy everything up

		; --- Now handle unshading -- this is easy :-/ ---

50dbox_shade	BIC	R6,R6,#&f000000f	;Clear some bits
		BIC	R6,R6,#&00e00000	;Clear some more bits
		BIC	R6,R6,#&00000ff0	;Clear yet more bits

		BIC	R5,R5,#&0f500000	;Clear another load of bits
		BIC	R5,R5,#&000ff000	;And the last load of bits

		ORR	R5,R5,R6		;Now merge them all together
		MOV	R14,#-1			;Update all of the flags
		ADD	R0,R13,#8		;Point to the flags masks
		STMIA	R0,{R5,R14}		;Save the masks away
		SWI	Wimp_SetIconState	;Now flicker the icon

		; --- Tidy everything up finally ---

80dbox_shade	ADD	R13,R13,#40		;Restore the stack position
		LDR	R0,[R10,#dbox__defn]	;Find the window definition
		LDR	R0,[R0,#64]		;Load the sprite area pointer
		SWI	XSculptrix_SetSpriteArea ;Set the sprite area up
		LDR	R1,[R13,#4]		;Get the icon handle back
		LDR	R0,[R10,#dbox__window]	;Get the window handle
		SWI	XSculptrix_UpdateIcon	;And redraw the 3D border
		LDMFD	R13!,{R0-R6,R10,PC}^	;Return to caller

		LTORG

; --- dbox_selectMany ---
;
; On entry:	R0 == dialogue box handle
;		R1 == pointer to icon handle list, -1 terminated
;		R2 == select action (0 == unselect, 1 == select, 2 == toggle)
;
; On exit:	--
;
; Use:		Changes the select state of a group of icons.

		EXPORT	dbox_selectMany
dbox_selectMany	ROUT

		STMFD	R13!,{R1,R3,R14}	;Save some registers
		MOV	R3,R1			;Remember this pointer
00		LDR	R1,[R3],#4		;Load next icon handle
		CMP	R1,#-1			;Is it the end of the list?
		BLNE	dbox_select		;No -- then do the select
		BNE	%b00			;And loop round again
		LDMFD	R13!,{R1,R3,PC}^	;And return to caller

		LTORG

; --- dbox_shadeMany ---
;
; On entry:	R0 == dialogue box handle
;		R1 == pointer to icon handle list, -1 terminated
;		R2 == shade action (0 == unshade, 1 == shade, 2 == toggle)
;
; On exit:	--
;
; Use:		Changes the shade state of a group of icons.

		EXPORT	dbox_shadeMany
dbox_shadeMany	ROUT

		STMFD	R13!,{R1,R3,R14}	;Save some registers
		MOV	R3,R1			;Remember this pointer
00		LDR	R1,[R3],#4		;Load next icon handle
		CMP	R1,#-1			;Is it the end of the list?
		BLNE	dbox_shade		;No -- then do the select
		BNE	%b00			;And loop round again
		LDMFD	R13!,{R1,R3,PC}^	;And return to caller

		LTORG

; --- dbox_isSelected ---
;
; On entry:	R0 == dialogue box handle
;		R1 == icon number
;
; On exit:	CS if the icon is selected, CC otherwise
;
; Use:		Returns whether an icon is currently selected.

		EXPORT	dbox_isSelected
dbox_isSelected	ROUT

		STMFD	R13!,{R0,R1,R14}	;Save the registers away
		SUB	R13,R13,#40		;Make space for an icon block
		LDR	R0,[R0,#dbox__window]	;Load the dialogue's window
		STMIA	R13,{R0,R1}		;Store them in the block
		MOV	R1,R13			;Point to the block
		SWI	Wimp_GetIconState	;Get the icon information
		LDR	R14,[R13,#24]		;Load the icon flags
		ADD	R13,R13,#40		;Recover the stack space
		TST	R14,#&00200000		;Check the selected bit
		LDMFD	R13!,{R0,R1,R14}	;Load the saved registers
		ORRNES	PC,R14,#C_flag		;If flag set, return with CS
		BICEQS	PC,R14,#C_flag		;Otherwise, clear carry

		LTORG

; --- dbox_radio ---
;
; On entry:	R0 == dialogue box handle
;		R1 == icon handle
;
; On exit:	--
;
; Use:		Checks to see if the icon is a radio button as defined by
;		Sapphire, i.e. button type 3 (debounced) and non-zero ESG.
;		If it is, it selects it, and deselects all other icons with
;		this ESG.

		EXPORT	dbox_radio
dbox_radio	ROUT

		STMFD	R13!,{R0-R4,R9,R10,R14}	;Save some registers
		MOV	R10,R0			;Get the dialogue handle
		MOV	R9,R1			;Look after the icon number

		; --- Locate the icon and check it's a radio button ---

		MOV	R0,R1			;Icon in R0 for dbox__icon
		BL	dbox__icon		;Find the icon definition
		LDR	R14,[R0,#16]		;Load the icon flags
		AND	R4,R14,#&0000f000	;Leave only the button type
		CMP	R4,#&00003000		;Make sure it's Debounced
		LDMNEFD	R13!,{R0-R4,R9,R10,PC}^	;No -- return right now
		ANDS	R4,R14,#&001f0000	;Leave only the ESG
		CMPNE	R4,#&001f0000		;Or 31 (i.e. it's shaded)
		LDMEQFD	R13!,{R0-R4,R9,R10,PC}^	;Yes -- return right now

		; --- The ESG is now in R4 -- process it ---

		MOV	R0,#-1			;Start from the beginning

00dbox_radio	MOV	R1,#&001f0000		;Mask out all but the ESG
		MOV	R2,R4			;Move ESG in to test it
		MOV	R3,#+1			;Search forwards nicely
		BL	dbox__find		;Get the next matching icon
		CMP	R0,#-1			;None found?
		LDMEQFD	R13!,{R0-R4,R9,R10,PC}^	;Return to caller then
		MOV	R1,R0			;Icon number in R1 required
		MOV	R0,R10			;Dialogue box handle in R0
		CMP	R1,R9			;Is this the clicked icon?
		MOVEQ	R2,#1			;Yes -- select it
		MOVNE	R2,#0			;No -- deselect it
		BL	dbox_select		;Change its selection state
		MOV	R0,R1			;Start search where we left
		B	%00dbox_radio		;And loop round again

		LTORG

;----- Clicking and unclicking icons ----------------------------------------

; --- dbox_slab ---
;
; On entry:	R0 == dialogue box handle
;		R1 == icon handle
;
; On exit:	May return an error
;
; Use:		Slabs an icon in properly, to give visual feedback when you
;		click it.

		EXPORT	dbox_slab
dbox_slab	ROUT

		STMFD	R13!,{R0-R2,R12,R14}	;Save some registers away
		WSPACE	dbox__wSpace		;Find my workspace pointer

		; --- Allocate a new block ---

		MOV	R0,#20			;Make space for a new block
		BL	sub_alloc		;Try to allocate the block
		BVS	%90dbox_slab		;If it failed, skip forward

		; --- Link the block into the list ---

		LDR	R14,dbox__clickList	;Load the old list head
		STR	R0,dbox__clickList	;Store this block as new head
		STR	R14,[R0,#0]		;And store link to next one

		; --- Now actually slab the icon ---

		ADD	R2,R0,#4		;Point to slab descriptor
		LDR	R0,[R13,#0]		;Get the saved dbox handle
		LDR	R0,[R0,#dbox__window]	;Get the window handle
		SWI	XSculptrix_SlabIcon	;Slab the icon in nicely
		LDMFD	R13!,{R0-R2,R12,PC}^	;Return to caller

		; --- Tidy up after an error ---

90dbox_slab	ADD	R13,R13,#4		;Skip past stacked R0
		LDMFD	R13!,{R1,R2,R12,R14}	;Load the saved registers
		ORRS	PC,R14,#V_flag		;Set V flag on exit

		LTORG

; --- dbox_unslab ---
;
; On entry:	--
;
; On exit:	CS if there are no more slabbed icons after this one, CC
;		if there are more left.
;
; Use:		Unslabs an icon slabbed with dbox_slab.  Icons are unslabbed
;		in reverse order to that in which they were slabbed.  The
;		carry flag is returned as an indication of whether there
;		are any more icons left in the list -- you can unslab all
;		icons in one go by doing:
;
;				BL	dbox_unslab
;				SUBCC	PC,PC,#12	;Avoids a label!
;
;		It is recommended that, if you are going to close a window,
;		you unslab icons within it *after* you close, but before you
;		actually destroy it, e.g.
;
;				LDR	R0,my_dbox
;				BL	dbox_close
;				BL	dbox_unslab
;				BL	dbox_destroy

		EXPORT	dbox_unslab
dbox_unslab	ROUT

		STMFD	R13!,{R0-R2,R12,R14}	;Save some registers away
		WSPACE	dbox__wSpace		;Find my workspace pointer
		LDR	R1,dbox__clickList	;Find the last slabbed icon

		; --- Get the descriptor to free ---

		CMP	R1,#0			;Is there one at all?
		LDMEQFD	R13!,{R0-R2,R12,R14}	;No -- restore the registers
		ORREQS	PC,R14,#C_flag		;And return with C set

		; --- Unslab the icon and unlink the block ---
		;
		; Make sure the hourglass stays off all this time.

		ADD	R2,R1,#4		;Point to the slab descriptor
		SUB	R13,R13,#8		;Make an hourglass status blk
		MOV	R0,R13			;Point to the block
		BL	hour_suspend		;Save the old state a while
		SWI	XSculptrix_UnslabIcon	;Unslab the icon nicely
		BL	hour_resume		;Resume the hourglass now
		ADD	R13,R13,#8		;And restore the stack
		LDR	R2,[R1,#0]		;Get the next field out
		STR	R2,dbox__clickList	;Store it as the new head

		; --- Free the block now ---

		MOV	R0,R1			;Point to the slab block
		MOV	R1,#20			;suballoc wants the size
		BL	sub_free		;Free the block again

		; --- Now return the status to the user ---

		CMP	R2,#0			;Was the next block null?
		LDMFD	R13!,{R0-R2,R12,R14}	;Restore all the registers
		ORREQS	PC,R14,#C_flag		;Yes -- return and set C
		BICNES	PC,R14,#C_flag		;No -- return and clear C

		LTORG

;----- Messing with dialogue box fields -------------------------------------

; --- dbox__fieldLen ---
;
; On entry:	R1 == icon number
;		R10 == dialogue box handle
;
; On exit:	R0 == length of the text in the icon
;
; Use:		Returns the length of the field in the given icon

dbox__fieldLen	ROUT

		STMFD	R13!,{R1,R14}		;Save some registers

		; --- Find the icon definition ---

		SUB	R13,R13,#40		;Make space for icon block
		LDR	R0,[R10,#dbox__window]	;Get the window handle
		STMIA	R13,{R0,R1}		;Store handles in block
		MOV	R1,R13			;Point at the block
		SWI	Wimp_GetIconState	;Find the *current* icon info

		; --- Get the icon flags and find the data ---

		LDR	R0,[R13,#24]		;Load the flags word
		ANDS	R0,R0,#1<<8		;Check indir flag (clever)
		BEQ	%10dbox__fieldLen	;Yes -- skip ahead a bit

		; --- Handle indirectedness ---

		LDR	R0,[R13,#28]		;Load the icon data pointer
		ADD	R13,R13,#40		;Reclaim the stack block
		LDMFD	R13!,{R1,R14}		;Unstack the registers
		B	str_len			;Find the string length

		; --- Handle nonindirectedness ---
		;
		; We know at this point that R0 is 0, because we used ANDS
		; not TST above.  This is a pointless optimisation.

10		ADD	R1,R13,#28		;Point to the data string
11		LDRB	R14,[R1],#1		;Get a byte from the string
		CMP	R14,#' '		;Is it the end yet?
		BLT	%12dbox__fieldLen	;Yes -- skip forward
		ADD	R0,R0,#1		;Bump on the counter
		CMP	R0,#12			;Is it maximum length yet?
		BLT	%11dbox__fieldLen	;No -- skip back again

		; --- Return the calculated length ---

12		ADD	R13,R13,#40		;Reclaim the stack again
		LDMFD	R13!,{R1,PC}^		;Return to caller

		LTORG

; --- dbox_setField ---
;
; On entry:	R0 == dialogue box handle
;		R1 == icon number to write to (may be -1 for title)
;		      flags in top byte if not -1:
;			dbFlag_dots (bit 31) == add `...' if text overflows
;		R2 == pointer to string to use
;
; On exit:	--
;
; Use:		Writes the string specified into the indirection buffer
;		for the given icon.  If the icon is not indirected, an
;		error is generated.  If the indirected buffer is too small,
;		the string is shortened by chopping off the beginning or
;		the end, according to the setting of the icon's right
;		justify flag.
;
;		The icon is only flickered if the text has actually changed.
;		The caret is moved correctly if it is within the icon to
;		prevent it `falling off' the end and deleting the validation
;		string, or being positioned incorrectly in centred icons if
;		the length changes.
;
;		Note that this routine requires a string to already be in
;		the buffer, and doesn't perform any substitution or other
;		transformations.  This helps to prevent buffer full errors
;		and similar problems.

		EXPORT	dbox_setField
dbox_setField	ROUT

		STMFD	R13!,{R0-R5,R14}	;Stash registers away

		; --- Handle the title bar nicely ---

		CMP	R1,#-1			;Does he want the title?
		BEQ	%30dbox_setField	;Yes -- jump ahead to do it

		; --- Find out about the icon ---

		AND	R4,R1,#&FF000000	;Get the flag bits out
		BIC	R1,R1,#&FF000000	;Leave just the icon number
		LDR	R0,[R0,#dbox__window]	;Get the dbox's window handle
		SUB	R13,R13,#40		;Make space for icon block
		STMIA	R13,{R0,R1}		;Store the info in it
		MOV	R1,R13			;Point to the icon block
		SWI	Wimp_GetIconState	;Get the icon's information

		; --- Make sure we can change the text ---

		LDR	R1,[R13,#24]		;Get the icon's flags
		TST	R1,#&100		;Check the indirected bit
		BEQ	%80dbox_setField	;It's an error if it's clear

		; --- Now find how much we actually have to copy ---

		LDR	R5,[R13,#36]		;Get the buffer length
		SUB	R5,R5,#1		;Take terminator into account
		MOV	R0,R2			;Point to the string to copy
		BL	str_len			;Find out how long it is
		SUBS	R0,R0,R5		;Find out the difference
		BICLE	R4,R4,#(1<<31)		;If it fits, don't add dots
		BLE	%00dbox_setField	;And skip ahead
		TST	R1,#1<<9		;Is it right aligned?
		ADDNE	R2,R2,R0		;Yes, chop off front
		ORRNE	R4,R4,#1		;And set a flag to remember

		; --- Copy the text into the buffer ---

00dbox_setField	LDR	R0,[R13,#28]		;Find the buffer address
		MOV	R3,#0			;Count the length too

10dbox_setField	CMP	R5,R3			;How much space left in buff?
		MOVLE	R1,#0			;None -- pretend null char
		LDRGTB	R1,[R2],#1		;Get a byte from the string
		CMP	R1,#' '			;Is it a control char?
		MOVLO	R1,#0			;Yes -- say it's a zero
		BLO	%15dbox_setField	;And don't bother with dots

		; --- Handle ellipsis generation ---

		TST	R4,#(1<<31)		;Do we put the ellipsis in?
		BEQ	%15dbox_setField	;No -- skip ahead then
		TST	R4,#1			;Are we right-justified?
		ADDNE	R14,R3,#1		;Yes -- just get the length
		SUBEQ	R14,R5,R3		;Otherwise find what's left
		CMP	R14,#4			;Are we within three?
		MOVLO	R1,#'.'			;Yes -- put in a dot then

		; --- Return to normality ---

15dbox_setField	LDRB	R14,[R0],#1		;Get one from the buffer
		CMP	R14,#' '		;Same for the buffer char
		MOVLO	R14,#0

		CMP	R1,R14			;Are they different
		ORRNE	R4,R4,#2		;Yes -- remember this
		STRNEB	R1,[R0,#-1]		;And store the different char

		CMP	R1,#0			;Is that end of the string?
		ADDNE	R3,R3,#1		;No -- bump the length on
		BNE	%10dbox_setField	;And go round for another

		; --- We've copied the string -- now update the icon ---

		TST	R4,#2			;Is the string different?
		BEQ	%20dbox_setField	;No -- skip ahead

		MOV	R1,#0
		STR	R1,[R13,#8]		;The EOR mask for setstate
		STR	R1,[R13,#12]		;The BIC mask for setstate
		MOV	R1,R13			;Point to the block
		SWI	Wimp_SetIconState	;Flicker the icon nastily

		; --- Now check for the caret ---

		SWI	Wimp_GetCaretPosition	;Find out where the caret is
		LDMIA	R13,{R2,R4}		;Get the window and icon
		ADD	R0,R13,#40		;Point past this block
		LDMIA	R0,{R0,R1}		;Get the old dbox and icon
		LDR	R0,[R0,#dbox__window]	;Get the window handle
		CMP	R0,R2			;Do the window handles match?
		CMPEQ	R1,R4			;And the icon handles?
		BNE	%20dbox_setField	;No -- skip ahead

		; --- Push the caret back a little ---

		LDR	R5,[R13,#20]		;Get the caret index
		CMP	R5,R3			;Is this bigger than new len?
		MOVGT	R5,R3			;Yes -- trim the index

		; --- Now put the caret in the right place ---

		MOV	R2,#-1			;Don't set the x coord
		MOV	R3,#-1			;Don't set the y coord
		MOV	R4,#-1			;Don't set the height
		SWI	Wimp_SetCaretPosition	;Put the caret in its place

		; --- Return nicely ---

20dbox_setField	ADD	R13,R13,#40		;Reclaim that temporary space
		LDMFD	R13!,{R0-R5,PC}^	;Return to caller

		; --- Caller wants to update the title bar ---

30dbox_setField	LDR	R14,[R0,#dbox__defn]	;Load the window definition
		LDR	R5,[R14,#56]		;Load the title bar's flags
		TST	R5,#&00000100		;Check the indirected bit
		BEQ	%80dbox_setField	;If clear, generate the error

		LDR	R1,[R14,#72]		;Load the buffer pointer
		LDR	R2,[R0,#dbox__window]	;Load the window handle
		LDR	R0,[R13,#8]		;Load the string pointer
		BL	winUtils_setTitle	;And set the title string
		LDMFD	R13!,{R0-R5,PC}^	;Return to caller

		; --- Icon wasn't indirected ---

80dbox_setField	ADR	R0,dbox__nind		;Point to error
		BL	msgs_error		;Translate the message
		SWI	OS_GenerateError

dbox__nind	DCD	1
		DCB	"dboxNIND",0

		LTORG

; --- dbox_getField ---
;
; On entry:	R0 == dialogue box handle
;		R1 == icon number to interrogate
;
; On exit:	R0, R1 preserved
;		R2 == pointer to the icon text
;
; Use:		Returns a pointer to the text associated with an icon.
;		Note that if the icon is *not* indirected, the text will
;		be copied into the scratchpad.  Otherwise you get a pointer
;		to the actual indirected data.  You shouldn't write to the
;		string returned at all -- dbox_setField is specially
;		designed to do that sort of thing very well (i.e. not
;		flickering the text unless it has to, truncating if it's too
;		long, and handling the caret correctly).  You *are* allowed
;		to zero	terminate the string if you want to, though.
;
;		Despite all the PRM's assurances to the contrary, chances
;		are the text will be terminated by some weird control char,
;		so you'll have to handle this, and not just assume it's
;		going to be null-terminated.
;
;		Note: The indirected case is immensely quick -- just load a
;		pointer.  The non-indirected case has been optimised as much
;		as possible.

		EXPORT	dbox_getField
dbox_getField	ROUT

		STMFD	R13!,{R0,R1,R10,R14}	;Save some registers

		; --- Find the icon defintion ---

		MOV	R10,R0			;Keep dialogue box handle
		MOV	R0,R1			;Put icon handle in R0
		BL	dbox__icon		;Find icon definition

		; --- Find out about indirectedness ---

		LDR	R14,[R0,#16]		;Load the icon flags word
		TST	R14,#1<<8		;Is the bit set?
		LDRNE	R2,[R0,#20]		;Yes -- load the pointer
		LDMNEFD	R13!,{R0,R1,R10,PC}^	;And return

		; --- Copy the text to the scratchpad ---

		ADD	R0,R0,#20		;Point to the text string
		LDMIA	R0,{R0,R1,R14}		;Load the 12 bytes of text
		STMIA	R11,{R0,R1,R14}		;Store them in scratchpad
		MOV	R0,#0			;Zero terminate nicely
		STRB	R0,[R11,#12]		;In case string is too long
		MOV	R2,R11			;Point to string in scratch
		LDMFD	R13!,{R0,R1,R10,PC}^	;Return to caller

		LTORG

;---- Other utility functions -----------------------------------------------

; --- dbox_eventHandler ---
;
; On entry:	R0 == dialogue box handle
;		R1 == pointer to handler routine
;		R2 == value to pass to handler in R10
;		R3 == value to pass to handler in R12
;
; On exit:	R0 preserved
;		R1 == pointer to old handler
;		R2 == old R10 value
;		R3 == old R12 value
;
; Use:		Sets up an event handler for a dialogue box, and returns
;		the previous one.  If the pointer to handler is 0, there is
;		no dialogue box event handler.

		EXPORT	dbox_eventHandler
dbox_eventHandler
		ROUT

		STMFD	R13!,{R4-R6,R14}	;Save some registers
		LDR	R14,[R0,#dbx__defn]	;Load the dbx pointer
		CMP	R14,#0			;Is there a dbx definition?
		ADDEQ	R14,R0,#dbox__proc	;Point to the correct user...
		ADDNE	R14,R0,#dbx__proc	;... handler
		LDMIA	R14,{R4-R6}		;Load the old values out
		STMIA	R14,{R1-R3}		;Store the new ones in
		MOV	R1,R4			;Move the old values to...
		MOV	R2,R5			;... the correct registers...
		MOV	R3,R6			;... for returning
		LDMFD	R13!,{R4-R6,PC}^	;Return to caller

		LTORG

; --- dbox_renderTitle ---
;
; On entry:	R0 == dialogue box handle
;		R1 == pointer to redraw block
;
; On exit:	--
;
; Use:		Renders a dialogue box's embedded title if there is one.

		EXPORT	dbox_renderTitle
dbox_renderTitle
		ROUT

		STMFD	R13!,{R0-R3,R10,R14}	;Save a load of registers

		MOV	R10,R0			;Move the handle into R10
		LDR	R0,[R10,#dbox__title]	;Get the icon number out
		CMP	R0,#-1			;Check there really is one
		LDMEQFD	R13!,{R0-R3,R10,PC}^	;Return to caller if not

		BL	dbox__icon		;Find the icon pointer
		MOV	R2,#0			;Group box type 0, please
		LDR	R3,[R10,#dbox__defn]	;Find the window definition
		LDR	R3,[R3,#72]		;Get the actual data pointer
		SWI	XSculptrix_PlotGroupBox	;Draw the group box

		LDMFD	R13!,{R0-R3,R10,PC}^	;Return to caller now

		LTORG

; --- dbox_setEmbeddedTitle ---
;
; On entry:	R0 == dialogue box handle
;		R1 == icon which should contain the embedded title
;
; On exit:	--
;
; Use:		Declares a given dialogue box as requiring an embedded title
;		(rather than the one the WindowManager put on).

		EXPORT	dbox_setEmbeddedTitle
dbox_setEmbeddedTitle
		STR	R1,[R0,#dbox__title]	;Store the icon number
		MOVS	PC,R14

; --- dbox_setClickDrag ---
;
; On entry:	R0 == dialogue box handle
;
; On exit:	--
;
; Use:		Sets a given dialogue box so that the user can move it by
;		dragging from any part of the window, not just the title
;		bar.

		EXPORT	dbox_setClickDrag
dbox_setClickDrag
		STMFD	R13!,{R14}		;Save a register
		LDR	R14,[R0,#dbox__flags]	;Load the flags word
		ORR	R14,R14,#dbFlag__drag	;Set the click-drag flag
		STR	R14,[R0,#dbox__flags]	;Save the flags back again
		LDMFD	R13!,{PC}^		;Return to caller

; --- dbox_hasTitle ---
;
; On entry:	R0 == dialogue box handle
;
; On exit:	CS if the dialogue box has a title bar, CC if not
;
; Use:		Informs the caller whether the dialogue box has a title bar.
;		This is mainly useful for other library sections which
;		conditionally add in embedded titles etc.

		EXPORT	dbox_hasTitle
dbox_hasTitle	ROUT

		STMFD	R13!,{R14}		;Save a register
		LDR	R14,[R0,#dbox__defn]	;Load the window definition
		LDR	R14,[R14,#28]		;Load the window flags
		TST	R14,#1<<31		;Using new gadget flags?
		BEQ	%10dbox_hasTitle	;No -- skip to handle this
		TST	R14,#1<<26		;Test the title bar flag
		B	%20dbox_hasTitle	;And skip the other test

10dbox_hasTitle	TST	R14,#1<<0		;Test the old-fashioned bit

20dbox_hasTitle	LDMFD	R13!,{R14}		;Restore the register I saved
		ORRNES	PC,R14,#C_flag		;If bit set, return carry
		BICEQS	PC,R14,#C_flag		;Otherwise clear carry

		LTORG

; --- dbox_window ---
;
; On entry:	R0 == dialogue box handle
;
; On exit:	R0 == the dialogue box's window handle
;
; Use:		Returns the Wimp window handle associated with a dialogue
;		box.  This may be useful if you want to perform lowlevel
;		Wimp operation on it, or to subclass it using win.

		EXPORT	dbox_window
dbox_window	LDR	R0,[R0,#dbox__window]	;Load the window handle
		MOVS	PC,R14			;Return to caller

; --- dbox_help ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Adds a help line to the current help message, read by
;		scanning the icon to which the help was sent for an `H'
;		validation string.

		EXPORT	dbox_help
dbox_help	ROUT

		STMFD	R13!,{R0-R4,R10,R12,R14} ;Save some registers
		WSPACE	dbox__wSpace		;Find my workspace quickly

		LDR	R10,dbox__eventDbox	;Find the helpful dbox
		LDR	R0,dbox__eventIcon	;Find the icon too
		CMP	R0,#0			;Is it a sensible number?
		BLT	%99dbox_help		;No -- skip to the end

		; --- Locate the validation string ---

		BL	dbox__icon		;Find the icon definition
		MOV	R1,#'H'			;Find `H' validation commands
		MOV	R2,#0			;Start from the beginning
		BL	winUtils_findValid	;Find the validation string
		BCC	%99dbox_help		;If not there, skip to end

		; --- Copy the message tag to scratchpad ---

		MOV	R0,R11			;Point to scratchpad
		MOV	R1,#0			;We are not escaped yet
		ADD	R2,R2,#1		;Skip past `H' character

10dbox_help	LDRB	R14,[R2],#1		;Get the next byte

		CMP	R14,#'\'		;Is it a backslash?
		CMPEQ	R1,#0			;Make sure it's not escaped
		MOVEQ	R1,#1			;Yes -- escape next char
		BEQ	%10dbox_help		;And loop for next char

		CMP	R14,#' ' 		;Is it a control character
		MOVLT	R14,#0			;Yes -- terminate string
		CMP	R14,#';'		;Is it validation string end?
		CMPEQ	R1,#0			;Make sure it's not escaped
		MOVEQ	R14,#0			;Yes -- terminate string
		STRB	R14,[R0],#1		;Store character in buffer
		CMP	R14,#0			;Was that the end?
		BNE	%10dbox_help		;No -- try for another one

		; --- Send the message to !Help ---

		MOV	R0,R11			;Point to buffer start again
		BL	msgs_lookup		;Lookup the message tag
		BL	help_add		;Add it to the help message

99dbox_help	LDMFD	R13!,{R0-R4,R10,R12,PC}^ ;No -- return right now

		LTORG

;----- Useful constants -----------------------------------------------------

; --- Ways of opening dialogue boxes ---

		^	0
dbOpen_current	#	1			;In its current position
dbOpen_centre	#	1			;Centred on the screen
dbOpen_pointer	#	1			;Centred over the pointer
dbOpen_givenY	#	1			;At a given height on screen
						;  R2 == y coordinate to open

dbOpen_trans	EQU	&00			;Make the dbox transient
dbOpen_persist	EQU	&80			;Make the dbox persistent
dbOpen_nonSub	EQU	&40			;Don't open as a submenu

; --- Dialogue box event codes ---

dbEvent_close	EQU	-2			;The user closed the dialogue
						;C flag ignored on exit

dbEvent_help	EQU	-3			;The user wants some help
						;R1 == icon number
						;C flag ignored on exit

dbEvent_OK	EQU	-4			;The user clicked OK
						;R1 == mouse button status
						;C flag ignored on exit

dbEvent_cancel	EQU	-5			;The user clicked Cancel
						;R1 == mouse button status
						;C flag ignored on exit

dbEvent_redraw	EQU	-6			;Redraw a single rectangle
						;R1 == pointer to redraw blk
						;R2,R3 == coords of origin
						;CS => don't do default draw

dbEvent_menu	EQU	-7			;User clicked Menu button
						;R1 == icon handle clicked
						;C flag ignored on exit

dbEvent_drag	EQU	-8			;User dragged an icon
						;R1 == mouse button status
						;R2 == icon handle dragged
						;C flag ignored on exit

dbEvent_save	EQU	-9			;User wants to import data
						;R1 == icon handle dropped on
						;R2 == filetype of data
						;R3 == pointer to filename
						;R4 == estimated file size
						;C flag ignored on exit

dbEvent_load	EQU	-10			;User wants to load data
						;R1 == icon handle dropped on
						;R2 == filetype of data
						;R3 == pointer to filename
						;R4 == estimated file size
						;C flag ignored on exit

dbEvent_key	EQU	-11			;User pressed a key
						;R1 == key code received
						;R2 == icon handle with caret
						;CC => unknown keypress
						;Key code has been translated

dbEvent_hint	EQU	-12			;Received a hint message
						;R2 == pointer to hint string

dbEvent_enter	EQU	-13			;Pointer has entered window

dbEvent_leave	EQU	-14			;Pointer has left window

; --- Other values ---

dbFlag_dots	EQU	(1<<31)			;Add dots if text overflows
						;  in dbox_setField

;----- Dialogue box data structure ------------------------------------------

		^	0

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

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

dbFlag__open	EQU	(1<<0)			;Dialogue box is on-screen
dbFlag__static	EQU	(1<<1)			;Dialogue box is static
dbFlag__rCaret	EQU	(1<<2)			;We have to restore the caret
dbFlag__drag	EQU	(1<<3)			;Clicking window starts move

;----- Workspace ------------------------------------------------------------

		^	0,R12
dbox__wStart	#	0

dbox__wFlags	#	4			;Various magic flags for me
dbox__clickList	#	4			;List of button slabbings
dbox__eventDbox	#	4			;Dbox last event happened to
dbox__eventIcon	#	4			;Icon number from last event

dbFlag__inited	EQU	(1<<0)			;The dbox system is running

dbox__wSize	EQU	{VAR}-dbox__wStart

		AREA	|Sapphire$$LibData|,CODE,READONLY

		DCD	dbox__wSize
		DCD	dbox__wSpace
		DCD	16
		DCD	dbox_init

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

		END
