
; drawX.s
;
; An example of various Sapphire features (MDW)
;
;  1994-1998 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; DrawX 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.
;
; DrawX 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 DrawX.  If not, write to the Free Software Foundation,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

;----- Notes ----------------------------------------------------------------
;
; This application is a DrawFile viewer -- not even slightly useful in
; itself (although it uses the same amount of memory as Draw needs
; workspace!), but it does provide quite a neat demonstration of the
; following Sapphire features, and provides examples of how to use them:
;
; * dialogue boxes and custom dialogue box controls (arrow and numWrite)
; * error handling
; * memory management
; * drawfile rendering
; * data transfer
; * menu handling
; * command line processing
; * loading preferences
;
; It demonstrates dragging objects inside windows -- the code is fairly
; similar in structure to Glass's drag code, except that in the interests
; of keeping code size down I've not done rotating dash boxes.
;
; The other interesting feature exhibited is that the image for this
; application is just over half the size of the Acorn equivalent `DrawEx',
; which (a) doesn't support multiple drawfiles unless you hack it, (b)
; doesn't do zooming or dragging, and (c) doesn't support Help.
;
;							Mark Wooding

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

		GET	libs:header
		GET	libs:swis

		GET	libs:stream

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

		; --- Sapphire ---

		GET	sapphire:sapphire

		GET 	sapphire:akbd
		GET 	sapphire:alloc
		GET 	sapphire:banner
		GET 	sapphire:buttons
		GET 	sapphire:cmdLine
		GET	sapphire:dbox
		GET	sapphire:defHandler
		GET	sapphire:divide
		GET	sapphire:drag
		GET	sapphire:draw
		GET	sapphire:errorBox
		GET	sapphire:event
		GET	sapphire:fastMove
		GET	sapphire:flex
		GET	sapphire:heap
		GET	sapphire:help
		GET	sapphire:hour
		GET	sapphire:ibicon
		GET	sapphire:idle
		GET	sapphire:intKeys
		GET	sapphire:libOpts
		GET	sapphire:mbox
		GET	sapphire:menu
		GET	sapphire:menuDefs
		GET	sapphire:msgs
		GET	sapphire:progInfo
		GET	sapphire:ptr
		GET	sapphire:report
		GET	sapphire:res
		GET	sapphire:resources
		GET	sapphire:screen
		GET	sapphire:string
		GET	sapphire:warning
		GET	sapphire:wimp
		GET	sapphire:win
		GET	sapphire:winUtils

		GET	sapphire:choices.choices
		GET	sapphire:choices.options
		GET	sapphire:choices.prefs

		GET	sapphire:dbx.dbx
		GET	sapphire:dbx.arrow
		GET	sapphire:dbx.numWrite

		GET	sapphire:xfer.load
		GET	sapphire:xfer.save
		GET	sapphire:xfer.saveAs

		; --- Other external symbols ---

		IMPORT	version
		IMPORT	cright

;----- Constants ------------------------------------------------------------

		; --- Icon numbers ---

bnr__version	EQU	4			;The version display area
bnr__slider	EQU	6			;The progress slider bar

scale__write	EQU	0			;The scale writable icon
scale__up	EQU	1			;The scale up arrow button
scale__down	EQU	2			;The scale down arrow button
scale__toScreen	EQU	4			;The Scale to screen action
scale__toWindow	EQU	5			;The Scale to window action
scale__buttons	EQU	6			;The 8 set scale buttons
scale__ok	EQU	14			;And the OK button

info__name	EQU	1			;The DrawFile name area
info__size	EQU	3			;The file size area

		; --- Menu items ---

im__info	EQU	0			;The program info option
im__quit	EQU	1			;The quit application option

mm__info	EQU	0			;The file info option
mm__save	EQU	1			;The save drawfile option
mm__scale	EQU	2			;The scale option

		; --- Other constants ---

drawX__topY	EQU	940			;Maximum height for diagrams
drawX__bottomY	EQU	700			;Minimum height for diagrams
drawX__startY	EQU	844			;Initial height for diagrams

drawX__filetype	EQU	&AFF			;The filetype of a DrawFile

;----- Data structures ------------------------------------------------------

		; --- Window blocks ---

		^	0
dWin__window	#	4			;The window handle
dWin__flags	#	4			;Various flags
dWin__diagram	#	4			;Flex anchor for diagram
dWin__diagSize	#	4			;Size of the diagram
dWin__scale	#	4			;Scale of diagram (as 16.16)
dWin__extent	#	16			;The window's extent size
dWin__filename	#	256			;The diagram's filename
dWin__titleBar	#	256			;The diagram's title buffer
dWin__size	#	0

dwFlag__loaded	EQU	(1<<0)			;File has a good filename
dwFlag__hasDiag	EQU	(1<<1)			;There is an actual diagram
dwFlag__saving	EQU	(1<<2)			;This diagram is being saved
dwFlag__tent	EQU	(1<<3)			;Diagram block is tentative

		; --- Preferences data ---

		^	0
dPref__defScale	#	4			;Default document scale
dPref__size	#	0

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

		^	0,R12
drawX__wStart	#	4

drawX__prefs	#	dPref__size		;User's preferences
drawX__winY	#	4			;y position for next window
drawX__flags	#	4			;Various interesting flags
drawX__pollBlk	#	256			;The main polling block

dxFlag__drag	EQU	(1<<0)			;In midst of drag operation
dxFlag__ownPtr	EQU	(1<<1)			;We own the mouse pointer

drawX__wSize	EQU	{VAR}-drawX__wStart

;----- Initialisation -------------------------------------------------------

		AREA	|Client$$Code|,CODE,READONLY
		ENTRY

drawX__main	ROUT

		; --- Start up the library ---

		ADR	R0,drawX__appName	;Point to application name
		MOV	R1,#drawX__wSize	;Get my workspace size
		MOV	R2,#0			;Default stack size
		BL	sapphire_init		;Initialise the library
		BL	resources_init		;Use shared resource DLL
		BL	hour_init		;Initialise hourglass system
		BL	hour_on			;Turn on hourglass as needed

		MOV	R0,#0			;This is the first pass
		BL	drawX__cmdLine		;Read the command line
		SWICS	OS_Exit			;If helped, return to caller

		; --- Do various bits of initialisation ---

		ADR	R0,drawX__banner	;Point to banner block
		MOV	R1,R12			;Pass setup code my R12 value
		BL	banner			;Initialise the library
		BL	drawX__init		;Initialise workspace
		BL	drawX__iconbar		;Put the icon on the iconbar
		BL	drawX__getPrefs		;Load the preferences
		BL	heap_useHeap		;Allocate things from heap
		BL	ptr_blinkOn		;Enable caret blinking
		MOV	R0,#1			;This is the second pass
		BL	drawX__cmdLine		;Parse the command line

		; --- Enter the main loop ---

		BL	drawX__errors		;Set up the error return pt
00drawX__main	MOV	R0,#1			;Don't use idles pointlessly
		ADR	R1,drawX__pollBlk	;Point to my poll block
		BL	event_poll		;Get an event and handle it
		BLCC	drawX__unknowns		;Handle any unknown events
		BLCC	defHandler		;Supply a default action
		B	%00drawX__main		;And go round for another one

drawX__appName	DCB	"DrawX",0

drawX__banner	BANNER
		BNSLIDE	bnr__slider
		BNSETUP	drawX__bnrSetup
		BNEND

; --- drawX__errors ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Sets up the error handler to return to this routine's return
;		address

drawX__errors	ROUT

		STMFD	R13!,{R0-R2,R14}	;Save some registers
		BIC	R0,R14,#&FC000003	;Set up the resume address
		MOV	R1,R12			;Set up workspace on return
		ADD	R2,R13,#16		;And set up return stack ptr
		BL	report_register		;Set up the return point
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

		LTORG

; --- drawX__init ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Initialises DrawX's workspace.

drawX__init	ROUT

		STMFD	R13!,{R14}		;Save the link register
		MOV	R14,#drawX__startY	;Default diagram height
		STR	R14,drawX__winY		;Save the y coordinate
		MOV	R14,#0			;Clear the flags word
		STR	R14,drawX__flags	;Store that away
		LDMFD	R13!,{PC}^		;Return to caller

		LTORG

; --- drawX__bnrSetup ---
;
; On entry:	R0 == banner dialogue handle
;
; On exit:	--
;
; Use:		Fills in fields of the opening banner dialogue box.

drawX__bnrSetup	ROUT

		STMFD	R13!,{R0-R2,R14}	;Save some registers
		MOV	R1,#bnr__version	;Get the version icon
		LDR	R2,=version		;Find the version string
		BL	dbox_setField		;Fill in the icon nicely
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

		LTORG

; --- drawX__getPrefs ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Loads the application's preferences file.

drawX__getPrefs	ROUT

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

		; --- Initialise the preferences area ---

		ADR	R0,drawX__prefs		;Point to prefs buffer
		ADR	R1,drawX__defaults	;Point to default values
		MOV	R2,#dPref__size		;Size of the data
		BL	fastMove		;Initialise the buffer

		; --- Now read in the preferences ---

		BL	prefs_find		;Find the prefs chunk file
		ADR	R1,drawX__appName	;Use my name as the chunk
		ADR	R2,drawX__optDefs	;Point to options definition
		ADR	R3,drawX__prefs		;Point to preferences buffer
		MOV	R4,#-1			;It's not in a flex block
		BL	options_read		;Read the preferences

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

drawX__defaults	DCD	100			;Initialise default scale

drawX__optDefs	OPTINT	dPref__defScale,"DefaultScale"
		OPTEND

		LTORG

; --- drawX__cmdLine ---
;
; On entry:	R0 == 0 for first pass, 1 for second pass
;
; On exit:	CS if help given, CC otherwise
;
; Use:		Parses the DrawX command line, loading documents as required.

drawX__cmdLine	ROUT

		STMFD	R13!,{R0-R4,R10,R14}	;Save a load of registers
		MOV	R4,R0			;Look after pass flag
		SWI	OS_GetEnv		;Find the command line
		MOV	R1,R11			;Build in the scratchpad
		BL	cl_next			;Skip the application name
		BCC	%90drawX__cmdLine	;If nothing there, skip
		MOV	R3,R0			;Look after the cmdline ptr

		; --- The main parsing loop ---

00		MOV	R0,R3			;Point to command line
		ADR	R1,drawX__pollBlk	;Build in the poll block
		BL	cl_next			;Get next word from cmdline
		BCC	%90drawX__cmdLine	;If nothing there, skip

		MOV	R3,R0			;Keep place in string
		ADR	R0,drawX__cmdTable	;Point to keyword table
		BL	str_match		;Find which name matches
		ADDCS	PC,PC,R0,LSL #2		;If match, use branch table
		B	%05drawX__cmdLine	;If no match, load file

		B	%10drawX__cmdLine	;Give help to the user
		B	%15drawX__cmdLine	;Enable Choices support
		B	%20drawX__cmdLine	;Use a Dynamic Area

		; --- Load a file ---

05		TST	R4,#1			;Which pass is this?
		BEQ	%00drawX__cmdLine	;First -- don't load then

		MOV	R0,R1			;Point to filename again
		MOV	R10,#0			;No diagram handle yet
		BL	drawX__loadFile		;Try loading the file
		BLVC	drawX__loaded		;If loaded, make it nice
		MOVVS	R1,#1			;Otherwise set up error
		BLVS	drawX__loadFail		;And tidy up after it
		B	%00drawX__cmdLine	;And parse more command line

		; --- Give command line help ---

10		ADR	R0,drawX__cmdHelp	;Point to command line help
		MOV	R1,#0			;Use internal dictionary
		LDR	R2,=version		;Find my version string
		SWI	OS_PrettyPrint		;Print the string
		ORR	R4,R4,#2		;Remember we gave some help
		B	%00drawX__cmdLine	;And parse more command line

		; --- Enable the Choices application ---

15		TST	R4,#1			;Is this the first pass?
		MOVEQ	R0,#1			;Set Choices support on
		BLEQ	choices_useChoices	;Turn the support on
		B	%00drawX__cmdLine	;And parse more command line

		; --- Enable use of Dynamic Areas ---

20		TST	R4,#1			;Is this the first pass?
		ADREQ	R0,drawX__opts		;Yes -- point to options
		BLEQ	libOpts_register	;And register them
		B	%00drawX__cmdLine	;And parse more command line

		; --- Return to caller nicely ---

90		TST	R4,#2			;Did we give any help?
		LDMFD	R13!,{R0-R4,R10,R14}	;Restore registers
		ORRNES	PC,R14,#C_flag		;If so, set C flag on exit
		BICEQS	PC,R14,#C_flag		;Otherwise clear it

drawX__cmdTable	DCB	"-help",0
		DCB	"-choices",0
		DCB	"-dynArea",0
		DCB	0

drawX__cmdHelp	DCB	"DrawX v. ",27,0,13
		DCB	13
		DCB	"Usage: *DrawX [<options>] [<filename>]...",13
		DCB	13
		DCB	"Options allowed are:",13
		DCB	13
		DCB	"-choices",9,"Store options in Acorn's `Choices' "
		DCB	"directory",13
		DCB	"-dynArea",9,"Use a Dynamic Area for memory "
		DCB	"management",13
		DCB	0

drawX__opts	LIBOPT	"FLEX"			;Tell flex to use a dynamic
		DCD	1			;area if it can
		LOEND

		LTORG

;----- The icon bar ---------------------------------------------------------

; --- drawX__iconbar ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Installs the DrawX icon on the icon bar

drawX__iconbar	ROUT

		STMFD	R13!,{R0-R6,R14}	;Save some registers
		ADR	R0,drawX__sprName	;Point to the sprite name
		MOV	R1,#0			;No text required
		MOV	R2,#-1			;Left hand side of iconbar
		MOV	R3,#0			;Standard priority please
		ADR	R4,drawX__ibHandler	;Point to my event handler
		MOV	R5,#0			;No value in R10
		MOV	R6,R12			;Pass workspace in R12
		BL	ibicon_create		;Create the icon
		SWIVS	OS_GenerateError	;If it failed, kill the app
		LDMFD	R13!,{R0-R6,PC}^	;Return to caller

drawX__sprName	DCB	"!drawx",0

		LTORG

; --- drawX__ibHandler ---
;
; On entry:	R0 == icon bar event type
;		R1-R9 == dependent on event type
;
; On exit:	--
;
; Use:		Handles events directed at the icon bar.

drawX__ibHandler ROUT

		CMP	R0,#ibEvent_help	;Is it an event I recognise?
		ADDLS	PC,PC,R0,LSL #2		;Yes -- dispatch to handler
		MOVS	PC,R14			;Otherwise return to caller

		B	drawX__ibSelect		;Handle a mouse click
		B	drawX__ibMenu		;Handle a Menu click
		MOVS	PC,R14			;Ignore Adjust clicks
		B	drawX__ibData		;Handle a data save
		B	drawX__ibData		;Handle a data load
		B	drawX__ibHelp		;Handle help requests

		; --- Handle Select clicks on the icon ---

drawX__ibSelect	STMFD	R13!,{R0,R1,R10,R14}	;Save the link register
		MOV	R0,#0			;No filename for the diagram
		BL	drawX__newDiag		;Create a new diagram
		BLVC	drawX__setTitle		;Set the window's title
		BLVC	drawX__open		;Open the window nicely
		BLVC	drawX__cascade		;If it worked, do cascading
		MOVVS	R1,#1			;Otherwise report the error
		BLVS	errorBox		;With just an OK button
		LDMFD	R13!,{R0,R1,R10,PC}^	;Return to caller

		; --- Handle data transfer to the icon ---

drawX__ibData	STMFD	R13!,{R0,R1,R10,R14}	;Save some registers
		BL	event_last		;Find the last event code
		LDR	R0,[R1,#40]		;Load the data filetype
		MOV	R10,#0			;No diagram created currently
		BL	drawX__load		;Load the file
		LDMFD	R13!,{R0,R1,R10,PC}^	;Return to caller

		; --- Handle menu clicks on the icon ---

drawX__ibMenu	STMFD	R13!,{R0-R3,R14}	;Save some registers
		ADR	R0,drawX__imDef		;Point to the icon bar menu
		ADR	R1,drawX__imHnd		;Point to the handler code
		MOV	R2,R10			;Pass my R10 value along
		MOV	R3,R12			;And my workspace pointer
		BL	menu_create		;And create the menu
		LDMFD	R13!,{R0-R3,PC}^	;Return to caller

		; --- Define the icon bar menu ---

drawX__imDef	MENU	"DrawX"
		ITEM	"drxIMINFO"
		SUBWARN
		ITEM	"drxIMQUIT"
		MENUEND

		; --- Handle help requests ---

drawX__ibHelp	STMFD	R13!,{R0,R14}		;Save some registers
		ADR	R0,drawX__ibHlpMsg	;Point to the message tag
		BL	msgs_lookup		;Translate the message
		BL	help_add		;Add it to the help message
		LDMFD	R13!,{R0,PC}^		;Return to caller

drawX__ibHlpMsg	DCB	"drxhIB",0

		LTORG

; --- drawX__imHnd ---
;
; On entry:	R0 == menu event code
;		R1 == item number in menu
;
; On exit:	--
;
; Use:		Handles events for the icon bar menu.

drawX__imHnd	ROUT

		CMP	R0,#mEvent_help		;Is it a help request?
		BEQ	%50drawX__imHnd		;Yes -- handle it nicely
		CMP	R0,#mEvent_select	;Is it a normal selection?
		CMPNE	R0,#mEvent_subMenu	;Or opening a submenu
		MOVNES	PC,R14			;No -- ignore it then

		; --- Handle a menu selection event ---

		CMP	R1,#im__quit		;Is it the `Quit' option?
		SWIEQ	OS_Exit			;Yes -- quit the program
		CMP	R1,#im__info		;Or is it the `Info' option?
		MOVNES	PC,R14			;No -- ignore the event

		; --- Display info about DrawX ---

		STMFD	R13!,{R0-R2,R14}	;Save some registers
		ADR	R0,drawX__purpose	;Point to the purpose string
		BL	msgs_lookup		;Translate the message tag
		LDR	R1,=cright		;Point to copyright string
		LDR	R2,=version		;Find the version/date string
		BL	progInfo		;Display the dialogue box
		MOVVS	R1,#1			;If it failed, report error
		BLVS	errorBox		;With just an OK button
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

drawX__purpose	DCB	"drxPUR",0

		; --- Handle help requests for the menu ---

50drawX__imHnd	STMFD	R13!,{R0,R1,R14}	;Save some registers
		ADR	R0,drawX__imHlpMsg	;Point to the help string
		BL	menu_help		;Add message to help string
		LDMFD	R13!,{R0,R1,PC}^	;Return to caller

drawX__imHlpMsg	DCB	"drxhIM",0

		LTORG

;----- Scale dialogue box ---------------------------------------------------

; --- drawX__scale ---
;
; On entry:	R10 == diagram handle
;
; On exit:	--
;
; Use:		Displays a dialogue box allowing the user to scale the
;		a draw file.

drawX__scale	ROUT

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

		; --- Create the dialogue box ---

		ADR	R0,drawX__scaledb	;Point to the dialogue name
		BL	dbox_create		;Try to create the dialogue
		MOVVS	R1,#1			;If it failed, report the
		BLVS	errorBox		;error and quit
		BVS	%90drawX__scale
		MOV	R9,R0			;Look after the dbox handle

		; --- Set up the handler ---

		ADR	R1,drawX__scHnd		;Point to the handler
		MOV	R2,R10			;Pass the diagram in R10
		MOV	R3,R12			;Pass workspace in R12
		BL	dbox_eventHandler	;Set up the event handler

		ADR	R1,drawX__scaleDbx	;Point to the dbx def
		BL	dbx_declare		;Register the control types

		; --- Fill in the dialogue box ---

		BL	drawX__fillScale	;Fill in the scale

		; --- Display it on the screen ---

		MOV	R1,#dbOpen_pointer+dbOpen_trans
		BL	dbox_open		;Display the dialogue box

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

drawX__scaledb	DCB	"scale",0

drawX__scaleDbx	NUMWRT	scale__write,1,800
		ARROW	scale__up,1
		ARROW	scale__down,-1
		DBXEND

; --- drawX__fillScale ---
;
; On entry:	R9 == dialogue box handle
;		R10 == diagram handle
;
; On exit:	--
;
; Use:		Resets the scale dialogue box.

drawX__fillScale ROUT

		STMFD	R13!,{R0-R2,R14}	;Save some registers
		LDR	R2,[R10,#dWin__scale]	;Load the current scale
		ADD	R2,R2,R2,LSL #2		;Multiply it by 5 (x5)
		ADD	R2,R2,R2,LSL #2		;Multiply it by 5 (x25)
		MOV	R2,R2,LSR #14		;Divide it by 2^14
		MOV	R1,#scale__write	;Find the writable icon
		MOV	R0,R9			;Get the dialogue handle
		BL	numWrite_set		;Set the field up nicely
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

		LTORG

; --- drawX__scHnd ---
;
; On entry:	R0 == dialogue box event code
;		R1-R7 == depend on the event
;		R9 == dialogue box handle
;		R10 == diagram handle
;
; On exit:	--
;
; Use:		Handles events for the scale dialogue box.

drawX__scHnd	ROUT

		; --- Dispatch interesting events ---

		CMP	R0,#arrow_event		;Is it an arrow click?
		BEQ	%10drawX__scHnd		;Yes -- handle it then
		CMP	R0,#dbEvent_OK		;Is it an OK click?
		CMPNE	R0,#scale__ok
		BEQ	%30drawX__scHnd		;Yes -- handle it then
		CMP	R0,#scale__toScreen	;Is it the to screen button?
		BEQ	%50drawX__scHnd		;Yes -- handle it then
		CMP	R0,#scale__toWindow	;Is it the to window button?
		BEQ	%60drawX__scHnd		;Yes -- handle it then
		CMP	R0,#dbEvent_close	;Is it a close event?
		BEQ	%90drawX__scHnd		;Yes -- kill the dbox
		CMP	R0,#dbEvent_help	;Is it a help event?
		BEQ	%95drawX__scHnd		;Yes -- give the user help

		; --- It must be one of the standard scale buttons ---

		STMFD	R13!,{R0-R2,R14}	;Save some registers
		SUBS	R1,R0,#scale__buttons	;Get the first one's handle
		CMP	R1,#8			;Is it in range?
		LDMCSFD	R13!,{R0-R2,PC}^	;No -- return then

		ADR	R2,drawX__stdScale	;Point to the table
		LDR	R2,[R2,R1,LSL #2]	;Load the correct one
		MOV	R1,R0			;Get the actual icon handle
		MOV	R0,R9			;Get the dialogue box
		BL	dbox_slab		;Slab the button in nicely
		MOV	R1,#scale__write	;Find the writable icon
		BL	numWrite_set		;And fill it in nicely
		BL	dbox_unslab		;Unslab the button now
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

drawX__stdScale	DCD	33,50,66,80,100,120,200,400

		; --- Handle an arrow click ---

10drawX__scHnd	STMFD	R13!,{R0-R2,R14}	;Save some registers
		MOV	R1,#scale__write	;Find the writable icon
		MOV	R0,R9			;Get the dialogue box
		BL	numWrite_bump		;Bump the writable icon
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

		; --- Handle an OK click ---

30drawX__scHnd	STMFD	R13!,{R0-R2,R14}	;Save some registers
		MOV	R0,R9			;Get the dialogue box
		MOV	R1,#scale__ok		;Find the OK button
		BL	dbox_slab		;Slab the button nicely

		MOV	R1,#scale__write	;Find the writable icon
		BL	numWrite_read		;Read the icon value
		CMP	R2,#1			;Is the value too small?
		MOVLT	R2,#1			;Yes -- force it bigger
		MOV	R0,R2,LSL #16		;Scale the value up
		ADD	R0,R0,#50		;Make it round to nearest
		BL	div10			;Divide by 10 quickly
		BL	div10			;Divide by 10 again (/100)
		STR	R0,[R10,#dWin__scale]	;This is the new scale
		BL	drawX__doScale		;Set the scale nicely

		LDR	R14,[R13,#4]		;Load the button status
		CMP	R14,#1			;Is this an Adjust click?
		MOVNE	R0,R9			;Not Adjust -- get dbox
		BLNE	dbox_close		;Close the window
		BL	dbox_unslab		;Unslab the icon
		BLNE	dbox_destroy		;And destroy the dbox
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

		; --- Scale the diagram to the screen ---

50drawX__scHnd	STMFD	R13!,{R0-R5,R14}	;Save some registers
		MOV	R1,R0			;Get the icon handle
		MOV	R0,R9			;Get the dialogue box
		BL	dbox_slab		;Slab the button

		BL	screen_getInfo		;Get the screen information
		ADD	R14,R0,#screen_width	;Find the screen sizes
		LDMIA	R14,{R0,R1}		;Load them out
		SUB	R0,R0,#44		;Lose the scroll bar width
		SUB	R1,R1,#88		;And the titlebar height
		B	%70drawX__scHnd		;Do the scaling stuff

		; --- Scale the diagram to the window ---

60drawX__scHnd	STMFD	R13!,{R0-R5,R14}	;Save some registers
		MOV	R1,R0			;Get the icon handle
		MOV	R0,R9			;Get the dialogue box
		BL	dbox_slab		;Slab the button

		LDR	R14,[R10,#dWin__window]	;Load the window handle
		STR	R14,[R11,#0]		;Save it in the scratchpad
		MOV	R1,R11			;Point at it there
		SWI	Wimp_GetWindowState	;Find the window's info
		LDMIB	R11,{R0-R3}		;Load all the coordinates
		SUB	R0,R2,R0		;Get the window width
		SUB	R1,R3,R1		;Get the window height

		; --- Scale the diagram to fit in R0,R1 ---

70drawX__scHnd	LDR	R14,[R10,#dWin__diagram] ;Find the diagram
		ADD	R14,R14,#24		;Find the bounding box
		LDMIA	R14,{R2-R5}		;Load the coordinates out
		SUB	R4,R4,R2		;Get the diagram width
		SUB	R5,R5,R3		;And the height
		SUB	R0,R0,#32		;Compensate for the clearance
		SUB	R1,R1,#32		;On all four edges
		MOV	R0,R0,LSL #16		;Scale the target sizes up
		MOV	R3,R1,LSL #16

		MOV	R1,R4			;Get the original width
		BL	div_round		;Get the x scale factor
		MOV	R2,R0,LSL #8		;Look after this value

		MOV	R0,R3			;Get the y target size
		MOV	R1,R5			;And the original height
		BL	div_round		;Get the y scale factor

		CMP	R2,R0,LSL #8		;Which one's smaller?
		MOVGT	R2,R0,LSL #8		;Take that one
		STR	R2,[R10,#dWin__scale]	;This is the new scale
		BL	drawX__doScale		;Do everything nicely

		LDR	R14,[R13,#4]		;Load the button status
		CMP	R14,#1			;Is this an Adjust click?
		BLEQ	drawX__fillScale	;Yes -- reset writable area
		MOVNE	R0,R9			;Not Adjust -- get dbox
		BLNE	dbox_close		;Close the window
		BL	dbox_unslab		;Unslab the icon
		BLNE	dbox_destroy		;And destroy the dbox
		LDMFD	R13!,{R0-R5,PC}^	;Return to caller

		; --- Close the dialogue box ---

90drawX__scHnd	STMFD	R13!,{R0,R14}		;Save some registers
		MOV	R0,R9			;Get the dialogue handle
		BL	dbox_destroy		;Destroy the dialogue box
		LDMFD	R13!,{R0,PC}^		;Return to caller

		; --- Get some help on the dialogue ---

95drawX__scHnd	STMFD	R13!,{R0-R2,R14}	;Save some registers
		ADR	R0,drawX__scHlpMsg	;Point to the help message
		BL	msgs_lookup		;Translate it nicely
		BL	help_add		;Add it into the message
		SUB	R14,R1,#scale__buttons	;Subtract the buttons base
		CMP	R14,#8			;Is it in range?
		BCS	%96drawX__scHnd		;No -- skip to the end
		MOV	R0,R9			;Get the dialogue handle
		BL	dbox_getField		;Read the icon text
		ADR	R0,drawX__scButMsg	;Point to the help text
		BL	msgs_lookup		;Translate the message
		MOV	R1,R11			;Build it in the scratchpad
		BL	str_subst		;Build the string up
		BL	help_add		;Add this to the help message
96drawX__scHnd	BL	dbox_help		;Get icon-specific stuff
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

drawX__scHlpMsg	DCB	"drxhSCALE",0
drawX__scButMsg	DCB	"drxhSCBUT",0

		LTORG

; --- drawX__doScale ---
;
; On entry:	R10 == diagram handle
;
; On exit:	--
;
; Use:		Sets the diagram scale.  The tricky bit is ensuring that
;		the bit the user was looking at is still vaguely visible.
;		We assume that he's looking at the centre of the window and
;		do our best to keep that in the centre of the scaled view.

drawX__doScale	ROUT

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

		; --- Work out where the user's looking ---

		LDR	R14,[R10,#dWin__window]	;Load the diagram window
		SUB	R13,R13,#36		;Make space for a window blk
		STR	R14,[R13,#0]		;Save it in the block
		MOV	R1,R13			;Point to it there
		SWI	Wimp_GetWindowState	;Read its current position
		LDMIB	R13,{R0-R5}		;Load all that lot out
		SUB	R6,R2,R0		;Get the window width
		ADD	R4,R4,R6,ASR #1		;Find the horizontal centre
		SUB	R7,R3,R1		;Get the window height
		SUB	R5,R5,R7,ASR #1		;Find the vertical centre

		; --- Find where that is, relatively ---

		ADD	R14,R10,#dWin__extent	;Find the window extent
		LDMIA	R14,{R0-R3}		;Load that lot out
		ADD	R0,R0,#16		;Compensate for the border
		ADD	R1,R1,#16
		SUB	R2,R2,#16
		SUB	R3,R3,#16
		SUB	R4,R4,R0		;Get pos rel. to wind left
		SUB	R5,R5,R1		;Get pos rel. to wind bottom
		SUB	R2,R2,R0		;Get window extent width
		SUB	R3,R3,R1		;Get window extent height

		MOV	R0,R4,LSL #16		;Scale up horizontal pos
		MOV	R1,R2			;Get extent width
		BL	div_round		;Find the proportion nicely
		MOV	R4,R0			;Look after it

		MOV	R0,R5,LSL #16		;Scale up vertical pos
		MOV	R1,R3			;Get extent height
		BL	div_round		;Find the proportion nicely
		MOV	R5,R0			;Look after that too

		; --- Reset the extent and redo the scroll stuff ---

		BL	drawX__setExtent	;Set the new extent
		ADD	R14,R10,#dWin__extent	;Find the new window extent
		LDMIA	R14,{R0-R3}		;Load that lot out
		ADD	R0,R0,#16		;Compensate for the border
		ADD	R1,R1,#16
		SUB	R2,R2,#16
		SUB	R3,R3,#16
		SUB	R2,R2,R0		;Get the new extent width
		SUB	R3,R3,R1		;Get the new extent height
		MUL	R2,R4,R2		;Work out the new relative
		MUL	R3,R5,R3		;scroll positions
		ADD	R4,R0,R2,ASR #16	;And convert them to
		ADD	R5,R1,R3,ASR #16	;absolute ones
		SUB	R4,R4,R6,ASR #1		;And uncentre them
		ADD	R5,R5,R7,ASR #1		;

		; --- Scroll the window nicely ---

		ADD	R14,R13,#20		;Point to the scroll offsets
		STMIA	R14,{R4,R5}		;Save them in there
		MOV	R1,R13			;Point to the block
		SWI	Wimp_OpenWindow		;Open the window
		ADD	R13,R13,#36		;Reclaim the stack space

		; --- Redraw the window ---

		LDR	R0,[R10,#dWin__window]	;Load the window handle
		ADD	R14,R10,#dWin__extent	;Find the window extent
		LDMIA	R14,{R1-R4}		;Load the coordinates out
		SWI	Wimp_ForceRedraw	;Redraw the whole view
		LDMFD	R13!,{R0-R7,PC}^	;Return to caller

		LTORG

; --- drawX__setExtent ---
;
; On entry:	R10 == a diagram handle
;
; On exit:	--
;
; Use:		Resets the diagram window's extent so that the diagram
;		fits inside it at its current scale.

drawX__setExtent ROUT

		STMFD	R13!,{R0-R4,R14}	;Save some registers
		LDR	R14,[R10,#dWin__diagram] ;Find the diagram address
		ADD	R14,R14,#24		;Point to the bounding box
		LDMIA	R14,{R1-R4}		;Load them out nicely
		LDR	R0,[R10,#dWin__scale]	;Load the scale factor
		MOV	R0,R0,LSR #8		;Scale that down a bit
		MUL	R1,R0,R1		;Scale up all the positions
		MUL	R2,R0,R2
		MUL	R3,R0,R3
		MUL	R4,R0,R4
		MOV	R14,#16			;Add a gap round the edge
		RSB	R1,R14,R1,ASR #16	;And scale them back down
		RSB	R2,R14,R2,ASR #16
		ADD	R3,R14,R3,ASR #16
		ADD	R4,R14,R4,ASR #16
		ADD	R14,R10,#dWin__extent	;Point to the extent block
		STMIA	R14,{R1-R4}		;Save them away there
		LDR	R0,[R10,#dWin__window]	;Load the window handle
		ADD	R1,R10,#dWin__extent	;Point to the coordinates
		SWI	Wimp_SetExtent		;Set the new extent
		LDMFD	R13!,{R0-R4,PC}^	;Return to caller

		LTORG

; --- drawX__refresh ---
;
; On entry:	R10 == diagram handle
;
; On exit:	--
;
; Use:		Refreshes a diagram after changing its extent

drawX__refresh	ROUT

		STMFD	R13!,{R0-R4,R14}
		LDR	R0,[R10,#dWin__window]	;Load the window handle
		STR	R0,[R11,#0]		;Save it in the scratchpad
		MOV	R1,R11			;Point to it there
		SWI	Wimp_GetWindowState	;Get the window's position
		SWI	Wimp_OpenWindow		;Open the window there
		LDR	R0,[R10,#dWin__window]	;Load the window handle
		ADD	R14,R10,#dWin__extent	;Find the window's extent
		LDMIA	R14,{R1-R4}		;Load the coordinates
		SWI	Wimp_ForceRedraw	;And clear the window
		LDMFD	R13!,{R0-R4,PC}^	;Return to caller

		LTORG

;----- The main window handler ----------------------------------------------

; --- drawX__newDiag ---
;
; On entry:	R0 == pointer to filename, or 0 for none
;
; On exit:	VC and R10 == pointer to a pristine new diagram structure, or
;		VS and R0 == pointer to error, and R10 corrupted
;
; Use:		Creates a new diagram block and window, and opens it on
;		the screen.

drawX__newDiag	ROUT

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

		; --- Allocate a block of memory for the diagram ---

		MOV	R0,#dWin__size		;Get the size of the block
		BL	alloc			;Try to get the memory
		BLCS	alloc_error		;If no memory, get error
		BCS	%99drawX__newDiag	;And tidy everything up
		MOV	R10,R0			;Look after the block handle

		; --- Fill in the block and set things up ---

		MOV	R14,#0			;No diagram currently
		STR	R14,[R10,#dWin__diagram] ;So clear the diagram
		LDR	R0,drawX__prefs+dPref__defScale
		MOV	R0,R0,LSL #16		;Scale it up
		ADD	R0,R0,#50		;Round to nearest
		BL	div10			;And divide by 10
		BL	div10			;And again -- now in 16.16
		STR	R0,[R10,#dWin__scale]	;And save that too
		MOV	R0,#0			;Left hand side
		MOV	R1,#0			;Bottom edge
		MOV	R2,#640			;Right hand side
		MOV	R3,#512			;Top edge
		ADD	R14,R10,#dWin__extent	;Point to the extent block
		STMIA	R14,{R0-R3}		;Save the initial extent
		MOV	R3,#0			;No flags currently

		; --- Work out the file's name ---

		LDR	R0,[R13,#0]		;Load the filename pointer
		CMP	R0,#0			;Is it defined properly?
		ORRNE	R3,R3,#dwFlag__loaded	;Yes -- say the file's loaded
		ADREQ	R0,drawX__untitled	;No -- point to default
		BLEQ	msgs_lookup		;And translate the message
		MOV	R1,R0			;This is the source string
		ADD	R0,R10,#dWin__filename	;Point to filename buffer
		BL	str_cpy			;Copy it in there nicely

		STR	R3,[R10,#dWin__flags]	;Save the flags word away

		; --- Now create a new window ---

		MOV	R0,R11			;Point at the scratchpad
		ADR	R1,drawX__winDef	;Point at the window def
		MOV	R2,#drawX__winSize	;Get the size of the window
		BL	fastMove		;Copy it to the scratchpad

		LDMIB	R11,{R0-R2}		;Load top and bottom y
		SUB	R0,R2,R0		;Get height in R0
		LDR	R2,drawX__winY		;Get current cascade coord
		SUB	R0,R2,R0		;Work out correct bottom
		STMIB	R11,{R0-R2}		;Store back in the scratchpad

		ADD	R14,R10,#dWin__titleBar	;Point to the title buffer
		STR	R14,[R11,#72]		;Save this as buffer pointer

		MOV	R1,R11			;Point to the scratchpad
		SWI	XWimp_CreateWindow	;Try to create the window
		BVS	%98drawX__newDiag	;If it failed, tidy up
		STR	R0,[R10,#dWin__window]	;Save the window handle

		; --- Register the window's event handler ---

		ADR	R1,drawX__winHnd	;Point to the handler
		MOV	R2,R10			;Pass diagram block in R10
		MOV	R3,R12			;And workspace in R12
		BL	win_eventHandler	;Register the event handler
		BVS	%97drawX__newDiag	;If it failed, tidy up

		LDMFD	R13!,{R0-R3,R14}	;Restore all the registers
		BICS	PC,R14,#V_flag		;And return with V clear

		; --- Various things went wrong ---

97		MOV	R3,R0			;Look after error pointer
		ADD	R1,R10,#dWin__window	;Point at the window handle
		SWI	Wimp_DeleteWindow	;Don't want it any more
		MOV	R0,R3			;Restore the error pointer

98		MOV	R3,R0			;Look after error pointer
		MOV	R0,R10			;Point at my diagram block
		BL	free			;Don't want that any more
		MOV	R0,R3			;Restore the error pointer

99		ADD	R2,R0,#4		;Point at the error text
		ADR	R0,drawX__newErr	;Point to error message
		BL	msgs_error		;Do clever things with it
		ADD	R13,R13,#4		;Don't restore R0 on exit
		LDMFD	R13!,{R1-R3,R14}	;Unstack all the registers
		ORRS	PC,R14,#V_flag		;And return with V set

drawX__newErr	DCD	1
		DCB	"drxNEWERR",0

drawX__untitled	DCB	"drxUNT",0

drawX__winDef	DCD	320,0,960,512,0,0,-1	;Initial window position
		DCD	&ff000002		;All gadgets, moveable
		DCB	7,2,7,0,3,1,12,0	;Normal window colours
		DCD	0,0,640,512		;Initial work area size
		DCD	&00000139		;Indirect the title text
		DCD	(7<<12)			;Respond to click and drag
		DCD	1			;Use Wimp sprite area FWIW
		DCW	1,0			;Allow title bar hiding
		DCD	0,-1,256		;Title bar indirection stuff
		DCD	0			;No icons defined

drawX__winSize	EQU	{PC}-drawX__winDef	;Size of the window block

		LTORG

; --- drawX__winHnd ---
;
; On entry:	R0 == event code
;		R1 == pointer to event data
;		R10 == diagram handle
;
; On exit:	CS if I handled the event, CC otherwise
;
; Use:		Handles events directed at a diagram window.

drawX__winHnd	ROUT

		CMP	R0,#19			;Do I recognise the event?
		ADDCC	PC,PC,R0,LSL #2		;Yes -- dispatch it then
		MOVS	PC,R14			;Otherwise ignore it

		MOVS	PC,R14			;NullReasonCode
		B	drawX__redraw		;RedrawWindowRequest
		MOVS	PC,R14			;OpenWindowRequest
		B	drawX__killDiag		;CloseWindowRequest
		B	drawX__ptrLeave		;PointerLeavingWindow
		B	drawX__ptrEnter		;PointerEnteringWindow
		B	drawX__click		;MouseClicked
		MOVS	PC,R14			;UserDragBox
		MOVS	PC,R14			;KeyPressed
		MOVS	PC,R14			;MenuSelection
		MOVS	PC,R14			;ScrollRequest
		MOVS	PC,R14			;LoseCaret
		MOVS	PC,R14			;GainCaret
		MOVS	PC,R14			;PollWordNonZero
		MOVS	PC,R14			;UndefinedEvent_14
		MOVS	PC,R14			;UndefinedEvent_15
		MOVS	PC,R14			;UndefinedEvent_16
		B	drawX__message		;UserMessage
		B	drawX__message		;UserMessageRecorded

		LTORG

; --- drawX__killDiag ---
;
; On entry:	R10 == diagram handle
;
; On exit:	CS
;
; Use:		Destroys a diagram.

drawX__killDiag	ROUT

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

		; --- Kill the diagram itself, if it exists ---

		LDR	R0,[R10,#dWin__diagram]	;Load the diagram anchor
		CMP	R0,#0			;Is it a sensible value?
		ADDNE	R0,R10,#dWin__diagram	;Yes -- point to it then
		BLNE	flex_free		;And free the memory it used

		; --- Destroy the diagram's window ---

		LDR	R0,[R10,#dWin__window]	;Get the window handle
		ADR	R1,drawX__winHnd	;Point to the handler
		MOV	R2,R10			;Pass diagram block in R10
		MOV	R3,R12			;And workspace in R12
		BL	win_removeEventHandler	;Remove my event handler

		ADD	R1,R10,#dWin__window	;Point to the window handle
		SWI	Wimp_DeleteWindow	;Destroy the window

		; --- Destroy the diagram anchor block ---

		MOV	R0,R10			;Point at the diagram block
		BL	free			;Destroy it
		LDMFD	R13!,{R0-R3,R14}	;Return to caller
		ORRS	PC,R14,#C_flag

		LTORG

; --- drawX__ptrEnter ---
;
; On entry:	R10 == diagram handle
;
; On exit:	--
;
; Use:		Makes the mouse pointer turn into a magnifying glass over
;		a diagram window.

drawX__ptrEnter	ROUT

		STMFD	R13!,{R0-R2,R14}	;Save some regisers
		LDR	R14,drawX__flags	;Load the flags word
		ORR	R14,R14,#dxFlag__ownPtr	;We own the pointer now
		STR	R14,drawX__flags	;Store the flags back

		LDR	R14,[R10,#dWin__diagram] ;Load the diagram pointer
		CMP	R14,#0			;Is it defined?
		ADRNE	R0,drawX__ptrName	;Yes -- point to the name
		MOVNE	R1,#12			;Get the hot x position
		MOVNE	R2,#6			;And the hot y position
		BLNE	ptr_setShape		;And set the pointer position
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

drawX__ptrName	DCB	"ptr_zoom",0

		LTORG

; --- drawX__ptrLeave ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Makes the pointer look normal again when it leaves a
;		diagram window.

drawX__ptrLeave	ROUT

		STMFD	R13!,{R14}		;Save link register
		LDR	R14,drawX__flags	;Load the flags word
		BIC	R14,R14,#dxFlag__ownPtr	;Don't own pointer any more
		STR	R14,drawX__flags	;Save the flags back
		TST	R14,#dxFlag__drag	;Are we dragging?
		BLEQ	ptr_resetShape		;No -- remove the pointer
		LDMFD	R13!,{PC}^		;And return to caller

		LTORG

; --- drawX__redraw ---
;
; On entry:	R1 == pointer to a redraw block
;		R10 == diagram handle
;
; On exit:	--
;
; Use:		Redraws a diagram window.

drawX__redraw	ROUT

		STMFD	R13!,{R0-R3,R14}	;Save some registers
		SWI	Wimp_RedrawWindow	;Start the redraw operation
		CMP	R0,#0			;Is there anything to do?
		BEQ	%90drawX__redraw	;No -- skip to the end

		; --- Do a redraw of a diagram ---

10drawX__redraw	LDR	R0,[R10,#dWin__scale]	;Load the current scale
		ADD	R14,R10,#dWin__diagram	;Point to the diagram
		LDMIA	R14,{R2,R3}		;Load the address and size
		CMP	R2,#0			;Is there a diagram at all?
		BLNE	draw_render		;Yes -- then render it
		BL	drag_redraw		;And redraw the drag box
		SWI	Wimp_GetRectangle	;Get another rectangle
		CMP	R0,#0			;Is there more to do?
		BNE	%10drawX__redraw	;Yes -- do another rectangle

		; --- The redraw's over ---

90drawX__redraw	LDMFD	R13!,{R0-R3,R14}	;Restore registers
		ORRS	PC,R14,#C_flag		;Claim the event

; --- drawX__message ---
;
; On entry:	R1 == pointer to a message block
;		R10 == diagram handle
;
; On exit:	CC or CS, depending on whether I handled it
;
; Use:		Handles a message sent to a diagram window.

drawX__message	ROUT

		STMFD	R13!,{R0,R14}		;Save some registers
		LDR	R14,[R1,#16]		;Load the message type
		LDR	R0,=&502		;Get the help message code
		CMP	R0,R14			;Does it match?
		BEQ	%10drawX__message	;Yes -- deal with it then
		CMP	R14,#1			;Is it a Message_DataSave?
		CMPNE	R14,#3			;Or a Message_DataLoad?
		LDMNEFD	R13!,{R0,PC}^		;No -- return to caller
		LDR	R0,[R1,#40]		;Load the filetype word
		BL	drawX__load		;Load the file
		LDMFD	R13!,{R0,PC}^		;And return to caller

10		ADR	R0,drawX__viewHelp	;Point to the message
		BL	msgs_lookup		;Translate it nicely
		BL	help_add		;Add it to the help message
		LDMFD	R13!,{R0,PC}^		;Return to caller

drawX__viewHelp	DCB	"drxhDIAG",0

		LTORG

; --- drawX__open ---
;
; On entry:	R10 == diagram handle
;
; On exit:	--
;
; Use:		Opens a diagram window on the screen.

drawX__open	ROUT

		STMFD	R13!,{R0,R1,R14}	;Save some registers
		LDR	R14,[R10,#dWin__window]	;Get the window handle
		STR	R14,[R11,#0]		;Save it in the scratchpad
		MOV	R1,R11			;Point at it nicely
		SWI	Wimp_GetWindowState	;Find its current position
		MOV	R14,#-1			;Bring it to the top
		STR	R14,[R11,#28]		;Save it in `behind' word
		SWI	Wimp_OpenWindow		;And open the new window
		LDMFD	R13!,{R0,R1,PC}^	;Return to caller

		LTORG

; --- drawX__click ---
;
; On entry:	R1 == pointer to mouse click block
;		R10 == diagram handle
;
; On exit:	--
;
; Use:		Handles mouse clicks on a diagram.

drawX__click	ROUT

		STMFD	R13!,{R0-R5,R14}	;Save some registers
		LDR	R14,[R1,#8]		;Load the button type
		TST	R14,#&02		;Is it a menu click?
		BNE	%70drawX__click		;Yes -- handle it then
		LDR	R3,[R10,#dWin__diagram]	;Load the diagram pointer
		CMP	R3,#0			;Is it valid?
		TSTNE	R14,#&50		;Yes -- some kind of drag?
		BEQ	%90drawX__click		;No -- ignore it then

		; --- Start a drag operation ---

		LDR	R0,[R10,#dWin__window]	;Load the window handle
		MOV	R1,#0			;Give me update events
		ADR	R2,drawX__dragHandler	;Point to handler routine
		MOV	R3,#0			;No magic number
		MOV	R4,R10			;Pass diagram handle in R10
		MOV	R5,R12			;Pass workspace in R12
		BL	drag_start		;Start the drag operation

		LDR	R14,drawX__flags	;Load the flags word
		ORR	R14,R14,#dxFlag__drag	;We're now dragging something
		STR	R14,drawX__flags	;Save the flags back
		B	%90drawX__click		;And return to caller

		; --- Handle a Menu click on the window ---

70drawX__click	ADR	R0,drawX__mainMenu	;Point to the menu definition
		ADR	R1,drawX__mmHnd		;Point to the handler
		MOV	R2,R10			;Pass diagram handle in R10
		MOV	R3,R12			;Pass workspace in R12
		BL	menu_create		;Create the menu nicely

90drawX__click	LDMFD	R13!,{R0-R5,PC}^	;Return to caller

drawX__mainMenu	MENU	"DrawX"
		ITEM	"drxMMINFO"
		ISHADE	dWin__flags,dwFlag__hasDiag
		SUBWARN
		NOWARN
		ITEM	"drxMMSAVE"
		ISHADE	dWin__flags,dwFlag__hasDiag
		SUBWARN
		NOWARN
		ITEM	"drxMMSCALE"
		ISHADE	dWin__flags,dwFlag__hasDiag
		SUBWARN
		NOWARN
		MENUEND

		LTORG

; --- drawX__dragHandler ---
;
; On entry:	R0 == event code
;		R10 == diagram handle
;
; On exit:	--
;
; Use:		Handles a drag box.

drawX__dragHandler ROUT

		CMP	R0,#7			;Is it in range?
		ADDCC	PC,PC,R0,LSL #2		;Yes -- dispatch
		MOVS	PC,R14			;Otherwise ignore it

		B	drawX__redrawDragBox
		B	drawX__redrawDragBox
		B	drawX__redrawDragBox
		MOVS	PC,R14
		B	drawX__dragScroll
		B	drawX__dragDone
		B	drawX__dragCancel

		LTORG

; --- drawX__dragScroll ---
;
; On entry:	R1 == pointer to window state
;
; On exit:	--
;
; Use:		Scrolls the window during the drag.

drawX__dragScroll ROUT

		STMFD	R13!,{R0-R3,R14}	;Save some registers
		BL	drag_scroll		;Read the scroll position
		STMIA	R14,{R2,R3}		;Save the new scroll position
		SWI	Wimp_OpenWindow		;Do the open operation
		LDMFD	R13!,{R0-R3,PC}^	;And return to caller

		LTORG

; --- drawX__unknowns ---
;
; On entry:	R0 == event code
;		R1 == pointer to event data
;
; On exit:	CS if I handled it, CC if I didn't
;
; Use:		Handles unrecognised events.

drawX__unknowns	ROUT

		CMP	R0,#17			;Is it a UserMessage?
		CMPNE	R0,#18			;Or a UserMessageRecorded?
		MOVNES	PC,R14			;No -- ignore it then

		; --- Handle messages ---

		STMFD	R13!,{R14}		;Save a register
		LDR	R14,[R1,#16]		;Load the message action
		CMP	R14,#5			;Is it Message_DataOpen?
		LDMNEFD	R13!,{PC}^		;No -- ignore it then

		STMFD	R13!,{R1,R10}		;Save another register
		LDR	R0,[R1,#40]		;Load the filetype
		MOV	R10,#0			;I don't have a diagram yet
		BL	drawX__load		;Load a new diagram
		LDMFD	R13!,{R1,R10,R14}	;Unstack the resulting regs
		ORRCSS	PC,R14,#C_flag		;If it loaded, set C flag
		BICCCS	PC,R14,#C_flag		;Otherwise clear it

		LTORG

; --- drawX__dragCancel ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Cancels the drag.

drawX__dragCancel ROUT

		STMFD	R13!,{R14}		;Save a register
		LDR	R14,drawX__flags	;Load the current flags
		BIC	R14,R14,#dxFlag__drag	;Clear the dragging flag
		STR	R14,drawX__flags	;Save the flags back again
		TST	R14,#dxFlag__ownPtr	;Do we own the pointer?
		BLEQ	ptr_resetShape		;No -- clear the shape then
		LDMFD	R13!,{PC}^		;Return to caller

		LTORG

; --- drawX__dragDone ---
;
; On entry:	R1 == pointer to window state
;		R2,R3 == drag start position
;		R4,R5 == drag end position
;
; On exit:	--
;
; Use:		Handles the end of a drag operation.


drawX__dragDone	ROUT

		STMFD	R13!,{R0-R7,R14}	;Save some registers
		BL	drawX__dragCancel	;Cancel the drag

		; --- Now read the drag values ---

		ADD	R14,R13,#8		;Point to arguments on stack
		LDMIA	R14,{R4-R7}		;Move them to different regs

		CMP	R4,R6			;Make sure they're the right
		EORGT	R4,R4,R6		;... way round
		EORGT	R6,R4,R6
		EORGT	R4,R4,R6
		CMP	R5,R7
		EORGT	R5,R5,R7
		EORGT	R7,R5,R7
		EORGT	R5,R5,R7

		; --- Get the window sizes ---

		LDMIB	R1,{R0-R3}		;Load the coordinates
		SUB	R2,R2,R0		;Get the window width
		SUB	R3,R3,R1		;And the window height

		; --- Work out the new scale factor ---

		SUBS	R1,R6,R4		;Get the drag box width
		BEQ	%90drawX__dragDone	;If it's bad, return now
		ADD	R4,R4,R1,LSR #1		;Find the box's centre
		MOV	R0,R2,LSL #16		;And the window width
		MOV	R6,R2,LSR #1		;Look after the width
		BL	div_round		;Do the division
		MOV	R2,R0			;Look after the quotient

		SUBS	R1,R7,R5		;Get the drag box height
		BEQ	%90drawX__dragDone	;If it's bad, return now
		ADD	R5,R5,R1,LSR #1		;Find the box's centre
		MOV	R0,R3,LSL #16		;And the window height
		BL	div_round		;Do the division
		MOV	R3,R3,LSR #1		;Halve the height

		CMP	R2,R0			;Which one's smaller?
		MOVGT	R2,R0			;Use that one then
		LDR	R7,[R10,#dWin__scale]	;Load the current scale
		MOV	R1,R7,LSR #8		;Divide it down a bit
		MOV	R2,R2,LSR #8		;And divide the new one
		MUL	R0,R2,R1		;Multiply them up
		CMP	R0,#&300		;Is it smaller than 1%?
		MOVLT	R0,#&300		;Yes -- force it to 1%
		CMP	R0,#&80000		;Is it bigger than 800%?
		MOVGT	R0,#&80000		;Yes - force it to 800%
		STR	R0,[R10,#dWin__scale]	;Save the new scale factor
		BL	drawX__setExtent	;Set the new window extent
		MOV	R0,R0,LSL #8		;Scale up the new factor
		MOV	R1,R7			;Get the old scale factor
		BL	div_round		;Get the scale difference

		; --- Set the new scroll positions ---

		LDR	R1,[R13,#4]		;Find the window state
		MUL	R4,R0,R4		;Multiply left drag box side
		MUL	R5,R0,R5		;And the top edge
		RSB	R4,R6,R4,ASR #8		;Scale them down a bit
		ADD	R5,R3,R5,ASR #8		;Scale them down a bit
		ADD	R14,R1,#20		;Point to the scroll pos
		STMIA	R14,{R4,R5}		;Save the new ones in there
		SWI	Wimp_OpenWindow		;Open the window nicely

		; --- Now redraw the window ---

		LDR	R0,[R10,#dWin__window]	;Load the window handle
		ADD	R14,R10,#dWin__extent	;Find the new extents
		LDMIA	R14,{R1-R4}		;Load them out nicely
		SWI	Wimp_ForceRedraw	;Redraw that lot nicely

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

		LTORG

; --- drawX__mmHnd ---
;
; On entry:	R0 == menu event code
;		R1 == item number
;		R10 == diagram handle
;
; On exit:	--
;
; Use:		Handles events for the main diagram menu.

drawX__mmHnd	ROUT

		CMP	R0,#mEvent_help		;Does the user want help?
		BEQ	%70drawX__mmHnd		;Yes -- give him some
		CMP	R0,#mEvent_subMenu	;Is it a submenu event?
		CMPNE	R0,#mEvent_select	;Or a selection event?
		MOVNES	PC,R14			;No -- then quit

		; --- Handle a menu selection ---

		CMP	R1,#mm__scale		;Is it one I recognise?
		ADDLS	PC,PC,R1,LSL #2		;Yes -- then deal with it
		MOVS	PC,R14			;Otherwise ignore it

		B	%10drawX__mmHnd		;Display the info box
		B	drawX__save		;Start a save operation
		B	drawX__scale		;Display the scale dialogue

		; --- Display and handle the File info box ---

10drawX__mmHnd	STMFD	R13!,{R0-R3,R14}	;Save some registers
		ADR	R0,drawX__fInfodb	;Point to the dialogue name
		BL	dbox_create		;Try to create the dialogue
		BVS	%30drawX__mmHnd		;Handle an error if if failed

		MOV	R3,R0			;Look after the dbox handle
		ADD	R2,R10,#dWin__filename	;Point to the file's name
		MOV	R1,#info__name+(1<<31)	;Get the right icon number
		BL	dbox_setField		;Set the field up nicely

		LDR	R0,[R10,#dWin__diagSize] ;Load the diagram's size
		MOV	R1,R11			;Point to the scratchpad
		MOV	R2,#256			;Assume it's nice and big
		SWI	OS_ConvertFileSize	;Make it a nice size string
		MOV	R2,R11			;Point at the string
		MOV	R0,R3			;Get the dialogue handle
		MOV	R1,#info__size		;And find the size icon
		BL	dbox_setField		;Set the field up

		ADR	R1,drawX__fInfoHlp	;Point to the help text
		BL	dbox_setClickDrag	;Make dialogue box draggable
		BL	mbox			;Display the dialogue box
		LDMFD	R13!,{R0-R3,PC}^	;Return to caller

		; --- Couldn't create the dialogue ---

30drawX__mmHnd	MOV	R1,#1			;Just an OK button please
		BL	errorBox		;Display the error message
		LDMFD	R13!,{R0-R3,PC}^	;Return to caller

drawX__fInfodb	DCB	"drawInfo",0
drawX__fInfoHlp	DCB	"drxhFINFO",0

		; --- Handle help requests for the menu ---

70drawX__mmHnd	STMFD	R13!,{R0,R1,R14}	;Save some registers
		ADR	R0,drawX__mmHlpMsg	;Point to the help string
		BL	menu_help		;Add message to help string
		LDMFD	R13!,{R0,R1,PC}^	;Return to caller

drawX__mmHlpMsg	DCB	"drxhMM",0

		LTORG

; --- drawX__redrawDragBox ---
;
; On entry:	R1 == pointer to redraw block
;		R2,R3 == start positions
;		R4,R5 == end positions
;		R6,R7 == window origin
;		R10 == diagram handle
;
; On exit:	--
;
; Use:		Draws the drag box.

drawX__redrawDragBox ROUT

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

		; --- Set the coordinates up ---

		MOV	R14,R6
		ADD	R6,R5,R7
		ADD	R5,R4,R14
		ADD	R4,R3,R7
		ADD	R3,R2,R14		;Convert to screen coords

		; --- Set the correct colour ---

		MOV	R0,#0			;Background colour is white
		MOV	R1,#2			;Drag box is grey
		BL	drag_eorColour		;Set the EOR colour nicely

		; --- Plot the actual rectangle ---

		MOV	R0,#4			;Move cursor absolute
		MOV	R1,R3			;Get left hand side
		MOV	R2,R4			;And bottom corner
		SWI	OS_Plot			;And plot the first point
		MOV	R0,#21			;Draw line absolute
		MOV	R1,R5			;Get right hand side
		MOV	R2,R4			;And bottom corner
		SWI	OS_Plot			;And plot the bottom edge
		MOV	R0,#53			;Draw line absolute
		MOV	R1,R5			;Get right hand side
		MOV	R2,R6			;And top corner
		SWI	OS_Plot			;And plot the right hand edge
		MOV	R0,#53			;Draw line absolute
		MOV	R1,R3			;Get left hand side
		MOV	R2,R6			;And top corner
		SWI	OS_Plot			;And plot the top edge
		MOV	R0,#61			;Draw line absolute
		MOV	R1,R3			;Get left hand side
		MOV	R2,R4			;And bottom corner
		SWI	OS_Plot			;And plot the right edge

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

		LTORG

; --- drawX__setTitle ---
;
; On entry:	R10 == diagram handle
;
; On exit:	--
;
; Use:		Updates a diagram window's title from its current state.

drawX__setTitle	ROUT

		STMFD	R13!,{R0-R2,R14}	;Save some registers
		ADD	R0,R10,#dWin__filename	;Point to the filename
		ADD	R1,R10,#dWin__titleBar	;Point to the title buffer
		LDR	R2,[R10,#dWin__window]	;Load the window handle
		BL	winUtils_setTitle	;Set the window's title
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

		LTORG

; --- drawX__cascade ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Updates the y position for the next diagram window so that
;		it produces a pleasing `cascading' effect.

drawX__cascade	ROUT

		STMFD	R13!,{R14}		;Save a register
		LDR	R14,drawX__winY		;Load the current y position
		SUB	R14,R14,#48		;Decrement the counter
		CMP	R14,#drawX__bottomY	;Is it within range?
		MOVLT	R14,#drawX__topY	;No -- move it to the top
		STR	R14,drawX__winY		;Save the cascaded position
		LDMFD	R13!,{PC}^		;And return to caller

		LTORG

;----- Data transfer --------------------------------------------------------

; --- drawX__save ---
;
; On entry:	R10 == diagram handle to save
;
; On exit:	--
;
; Use:		Saves a diagram.

drawX__save	ROUT

		STMFD	R13!,{R0-R5,R14}	;Save lots of registers
		LDR	R14,[R10,#dWin__flags]	;Get the diagram's flags
		TST	R14,#dwFlag__loaded	;Does it have a nice name?
		ADREQ	R0,drawX__defName	;No -- find one then
		BLEQ	msgs_lookup		;Translate it nicely
		ADDNE	R0,R10,#dWin__filename	;Otherwise use the name
		MOV	R2,R0			;Put the name in R2
		LDR	R0,[R10,#dWin__diagSize] ;Load the diagram's size
		LDR	R1,=drawX__filetype	;Get the filetype nicely
		ADR	R3,drawX__saveTbl	;Point to the entry table
		MOV	R4,R10			;Pass diagram handle in R10
		MOV	R5,R12			;Pass workspace in R12
		BL	saveAs			;Display the dialogue box
		BVS	%90drawX__save		;If it failed, deal with it

		LDR	R14,[R10,#dWin__flags]	;Load the flags word
		ORR	R14,R14,#dwFlag__saving	;This window is saving
		STR	R14,[R10,#dWin__flags]	;Save the flags back
		LDMFD	R13!,{R0-R5,PC}^	;Return to caller

90drawX__save	MOV	R1,#1			;If it failed, report the
		BL	errorBox		;error with just an OK button
		LDMFD	R13!,{R0-R5,PC}^	;Return to caller

drawX__defName	DCB	"drxDEFN",0

drawX__saveTbl	DCB	"drxSVTB",0
		B	drawX__saveOver
		B	drawX__saveFile
		B	drawX__send
		MOVS	PC,R14
		B	drawX__saveFail

; --- drawX__saveOver ---
;
; On entry:	R10 == diagram handle
;
; On exit:	--
;
; Use:		Clears the diagram's `saving' flag.

drawX__saveOver	ROUT

		STMFD	R13!,{R14}		;Save a register
		LDR	R14,[R10,#dWin__flags]	;Load the flags word
		BIC	R14,R14,#dwFlag__saving	;Window not saving any more
		STR	R14,[R10,#dWin__flags]	;Save the flags back
		LDMFD	R13!,{PC}^		;Return to caller

		LTORG

; --- drawX__saveFile ---
;
; On entry:	R0 == pointer to filename
;		R1 == 0 if file is unsafe
;		R10 == diagram handle
;
; On exit:	May return error
;
; Use:		Saves a diagram to a given file.

drawX__saveFile	ROUT

		STMFD	R13!,{R0-R5,R14}	;Save some registers
		MOV	R2,R0			;Keep pointer to name
		CMP	R1,#0			;Is the file safe?
		ADDNE	R1,R10,#dWin__filename	;Find the file's current name
		BLNE	str_icmp		;Do they match?
		BEQ	%10drawX__saveFile	;Either -- don't confirm
		BL	res_exists		;Does the file exist?
		BCC	%10drawX__saveFile	;No -- skip onwards then

		; --- Make sure user wants to overwrite file ---

		ADR	R0,drawX__oWrite	;Point to skeleton
		BL	msgs_lookup		;Translate the message
		MOV	R1,R11			;Build in scratchpad
		BL	str_subst		;Build the warning message
		ADR	R1,drawX__owWarn	;Point to warning block
		BL	warning			;Get a response
		MOVCC	R0,#0			;If no then abort saving
		BCC	%99drawX__saveFile	;By making a null error

10		MOV	R1,R2			;Get the filename in R1
		MOV	R0,#10			;We're saving whole files
		LDR	R2,=drawX__filetype	;Get the filetype number
		ADD	R14,R10,#dWin__diagram	;Find the diagram address
		LDMIA	R14,{R4,R5}		;Load the address and size
		ADD	R5,R4,R5		;Convert size to limit ptr
		SWI	XOS_File		;Try to save the file
		BVS	%99drawX__saveFile	;If it failed, skip on

		LDR	R14,[R13,#4]		;Get the `safe' flag
		CMP	R14,#0			;Is the file safe?
		BEQ	%90drawX__saveFile	;No -- skip to the end

		ADD	R0,R10,#dWin__filename	;Point to the filename
		BL	str_cpy			;Copy the new one over
		LDR	R14,[R10,#dWin__flags]	;Load the flags word
		ORR	R14,R14,#dwFlag__loaded	;File has a good name now
		STR	R14,[R10,#dWin__flags]	;Save the flags back
		BL	drawX__setTitle		;Set the window's title

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

99		ADD	R13,R13,#4		;Don't restore R0 on exit
		LDMFD	R13!,{R1-R5,R14}	;Restore registers
		ORRS	PC,R14,#V_flag		;Return the error

drawX__oWrite	DCB	"drxCWRT",0

drawX__owWarn	BUTTON	"drxRPL"
		BCANCEL
		BUTEND

		LTORG

; --- drawX__send ---
;
; On entry:	R10 == diagram handle
;
; On exit:	R0 == pointer to diagram
;		R1 == size of diagram
;		CS
;
; Use:		Returns the diagram block so it can be sent to another
;		application.

drawX__send	ROUT

		ADD	R0,R10,#dWin__diagram	;Point to the diagram info
		LDMIA	R0,{R0,R1}		;Load the address and size
		ORRS	PC,R14,#C_flag		;No more data to send

		LTORG

; --- drawX__saveFail ---
;
; On entry:	R0 == pointer to an error, or 0
;		R1 == 1
;
; On exit:	--
;
; Use:		Reports an error during a save attempt.

drawX__saveFail	ROUT

		CMP	R0,#0			;Is there an error
		MOVEQS	PC,R14			;No -- return now then
		STMFD	R13!,{R0-R2,R14}	;Save some registers
		ADD	R2,R0,#4		;Point to error text
		ADR	R0,drawX__badSave	;Point to the message
		BL	msgs_error		;Translate it nicely
		MOV	R1,#1			;Set up the button count
		BL	errorBox		;Report the error
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

drawX__badSave	DCD	1
		DCB	"drxESF",0

		LTORG

; --- drawX__load ---
;
; On entry:	R0 == filetype of data to send
;		R10 == diagram handle, or 0 to create a new one
;
; On exit:	CS if it was handled, CC otherwise
;
; Use:		Loads a drawfile into a specified diagram, or into a newly
;		created one.

drawX__load	ROUT

		STMFD	R13!,{R0-R2,R14}	;Save some registers
		LDR	R14,=drawX__filetype	;Get the drawfile filetype
		CMP	R0,R14			;Do they match properly?
		BNE	%90drawX__load		;No -- return then

		; --- Disallow save from a window to itself ---

		CMP	R10,#0			;Is there a diagram?
		LDRNE	R14,[R10,#dWin__flags]	;Load the diagram's flags
		TSTNE	R14,#dwFlag__saving	;Is it currently saving?
		BNE	%80drawX__load		;Yes -- disallow this then

		; --- Start a load operation ---

		ADR	R0,drawX__loadTbl	;Point to the entry table
		MOV	R1,R10			;Pass on the diagram handle
		MOV	R2,R12			;And my workspace pointer
		BL	load			;Start the load operation
		LDMFD	R13!,{R0-R2,R14}	;Unstack registers
		ORRS	PC,R14,#C_flag		;And say we handled it

		; --- Report an error about saving ---

80drawX__load	ADR	R0,drawX__badLoad	;Point to the error block
		BL	msgs_error		;Translate the message
		MOV	R1,#1			;Only have an OK button
		BL	errorBox		;Report the error

90drawX__load	LDMFD	R13!,{R0-R2,R14}	;Unstack registers
		BICS	PC,R14,#C_flag		;And don't claim the event

drawX__loadTbl	B	drawX__newBuf
		B	load_killBuf
		B	load_extendBuf
		B	drawX__doneBuf
		B	drawX__loadFile
		B	drawX__loaded
		B	drawX__loadFail

drawX__badLoad	DCD	1
		DCB	"drxCSII",0

		LTORG

; --- drawX__loadNew ---
;
; On entry:	R0 == pointer to name to create new diagram with
;
; On exit:	VC and R10 == pointer to diagram, or VS and R0 == pointer
;		to error
;
; Use:		Creates a new diagram for a drawfile to be loaded into.

drawX__loadNew	ROUT

		STMFD	R13!,{R0-R3,R14}	;Save some registers
		BL	drawX__newDiag		;Create a new diagram
		BVS	%99drawX__loadNew	;Handle an error from that
		LDR	R14,[R10,#dWin__flags]	;Load the current flags
		ORR	R14,R14,#dwFlag__tent	;Remember it's tentative
		STR	R14,[R10,#dWin__flags]	;Save the flags back again
		LDMFD	R13!,{R0-R3,R14}	;Restore registers
		BICS	PC,R14,#V_flag		;And return with V clear

99		ADD	R13,R13,#4		;Don't restore R0 on exit
		LDMFD	R13!,{R1-R3,R14}	;Restore registers
		ORRS	PC,R14,#V_flag		;And return with V set

		LTORG

; --- drawX__killOld ---
;
; On entry:	R10 == diagram handle
;
; On exit:	--
;
; Use:		Removes the current drawfile being showin in the diagram.

drawX__killOld	ROUT

		STMFD	R13!,{R0,R14}		;Save some registers
		LDR	R0,[R10,#dWin__diagram]	;Load the diagram anchor
		CMP	R0,#0			;Does it actually exist?
		ADDNE	R0,R10,#dWin__diagram	;Yes -- point at the anchor
		BLNE	flex_free		;And free the block
		MOVNE	R14,#0			;Zero it out nicely
		STRNE	R14,[R10,#dWin__diagram] ;Save the new anchor ptr
		LDMFD	R13!,{R0,PC}^		;Return to caller

		LTORG

; --- drawX__newBuf ---
;
; On entry:	R0 == pointer to leafname of file
;		R1 == estimated size of file
;		R10 == diagram handle, or 0 to create a new one
;
; On exit:	If all went well, VC and
;		  R0 == pointer to load buffer
;		  R1 == size of load buffer
;		  R2 == pointer to flex anchor
;		  R10 == diagram handle
;		Otherwise, VS, R0 == pointer to error, and R1, R2 corrupted
;
; Use:		Creates a load buffer for loading a new diagram.

drawX__newBuf	ROUT

		STMFD	R13!,{R14}		;Save the link register
		CMP	R10,#0			;Is there a diagram?
		BLEQ	drawX__loadNew		;No -- get one then
		BLNE	drawX__killOld		;Yes -- destroy the old one
		ADDVC	R2,R10,#dWin__diagram	;If OK, point to anchor
		BLVC	load_initBuf		;And find a new buffer
		LDMFD	R13!,{PC}		;Return to caller

		LTORG

; --- drawX__doneBuf ---
;
; On entry:	R0 == pointer to diagram name
;		R1 == actual size of diagram
;		R2 == pointer to diagram flex anchor
;		R10 == diagram handle
;
; On exit:	--
;
; Use:		Wraps up a successful RAM receive of a draw file.

drawX__doneBuf	ROUT

		STR	R1,[R10,#dWin__diagSize] ;Save the diagram size
		B	load_doneBuf		;And set the flex block up

		LTORG

; --- drawX__loadFile ---
;
; On entry:	R0 == pointer to leafname of file to load
;		R1 == pointer to filename to read
;		R10 == diagram handle, or 0 to create a new one
;
; On exit:	If all went well, VC and R10 == diagram handle
;		Otherwise, VS, R0 == pointer to error
;
; Use:		Loads a diagram from a file.

drawX__loadFile	STMFD	R13!,{R0-R2,R14}	;Save some registers
		CMP	R10,#0			;Is there a diagram?
		BLEQ	drawX__loadNew		;No -- get one then
		BLNE	drawX__killOld		;Yes -- destroy the old one
		MOVVS	R10,#0			;If no diagram, clear R10
		ADDVC	R2,R10,#dWin__diagram	;If OK, point to anchor
		BLVC	load_file		;And load the diagram
		STRVC	R0,[R10,#dWin__diagSize] ;Save the diagram size
		STRVS	R0,[R13,#0]		;Otherwise return error
		LDMFD	R13!,{R0-R2,PC}		;Return to caller

		LTORG

; --- drawX__loaded ---
;
; On entry:	R10 == diagram handle
;
; On exit:	--
;
; Use:		Completes loading of a diagram.

drawX__loaded	ROUT

		STMFD	R13!,{R0,R1,R14}	;Save lots of registers
		LDR	R0,[R10,#dWin__diagram]	;Find the diagram address
		BL	draw_checkValid		;Make sure it's kosher
		MOVVS	R1,#1			;If not, set R1 == 1
		BLVS	drawX__loadFail		;And kill off the diagram
		BVS	%90drawX__loaded	;And return

		; --- Set everything up for the new diagram ---

		BL	drawX__setExtent	;Set the extents
		BL	drawX__refresh		;Refresh the window contents
		BL	drawX__setTitle		;Set the title string
		LDR	R14,[R10,#dWin__flags]	;Load the diagram flags
		TST	R14,#dwFlag__tent	;Was it tentative?
		BICNE	R14,R14,#dwFlag__tent	;Diagram not tentative now
		ORR	R14,R14,#dwFlag__hasDiag ;Diagram now has a drawfile
		STR	R14,[R10,#dWin__flags]	;Save the flags back again
		BLNE	drawX__open		;Yes -- open it on screen
		BLNE	drawX__cascade		;And cascade the thing too

90drawX__loaded	LDMFD	R13!,{R0,R1,PC}^	;Return to caller

		LTORG

; --- drawX__loadFail ---
;
; On entry:	R0 == pointer to error, or 0 if none
;		R1 == 1
;		R10 == diagram handle, or 0 if none
;
; On exit:	--
;
; Use:		Handles an error during loading a diagram.

drawX__loadFail	ROUT

		STMFD	R13!,{R0-R4,R14}	;Save some registers
		CMP	R10,#0			;Is there a diagram?
		BEQ	%50drawX__loadFail	;No -- just report error

		; --- Work out what to do ---
		;
		; If the window is new, delete it.  Otherwise just leave it
		; blank.

		LDR	R14,[R10,#dWin__flags]	;Load the flags word
		TST	R14,#dwFlag__tent	;Is it tentative?
		BLNE	drawX__killDiag		;Yes -- kill the diagram
		BNE	%50drawX__loadFail	;And skip ahead

		; --- Blank out a diagram ---

		BIC	R14,R14,#dwFlag__loaded+dwFlag__hasDiag
		STR	R14,[R10,#dWin__flags]	;Save the flags back again
		ADRL	R0,drawX__untitled	;Point to the blank name
		BL	msgs_lookup		;Translate the message
		MOV	R1,R0			;This is the source string
		ADD	R0,R10,#dWin__filename	;Point to filename buffer
		BL	str_cpy			;Copy it over
		BL	drawX__setTitle		;Set the window's title
		MOV	R1,#0			;Left hand side is 0
		MOV	R2,#0			;Bottom edge is 0 too
		MOV	R3,#640			;Window is 640 units wide
		MOV	R4,#512			;And 512 units high
		ADD	R14,R10,#dWin__extent	;Point to the extent block
		STMIA	R14,{R1-R4}		;Save them all away
		LDR	R0,[R10,#dWin__window]	;Load the window handle
		ADD	R1,R10,#dWin__extent	;Point to the coordinates
		SWI	Wimp_SetExtent		;Set the new extent
		BL	drawX__refresh		;Refresh the window contents

		; --- Report the error ---

50		LDR	R2,[R13,#0]		;Load the error pointer
		CMP	R2,#0			;Is it interesting?
		ADDNE	R2,R2,#4		;Yes -- point to error text
		ADRNE	R0,drawX__loadErr	;Point to the message
		BLNE	msgs_error		;Translate the error
		MOVNE	R1,#1			;Only one button please
		BLNE	errorBox		;And report the error

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

drawX__loadErr	DCD	1
		DCB	"drxELF",0

		LTORG

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

		END
