;
; template.s
;
; Load window template resources (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:alloc
		GET	sapphire:fastMove
		GET	sapphire:except
		GET	sapphire:mem
		GET	sapphire:msgs
		GET	sapphire:res
		GET	sapphire:resources
		GET	sapphire:resspr
		GET	sapphire:sapphire
		GET	sapphire:string

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

		AREA	|Sapphire$$Code|,CODE,READONLY

; --- tpl__find ---
;
; On entry:	R0 == pointer to name to find
;
; On exit:	CS if template found in list, and
;		  R0 == pointer to template block (internal format)
;		else CC if in shared resource
;		  R0 == pointer to embedded template definition
;		May return an error
;
; Use:		Finds a named template in the list.

tpl__find	ROUT

		ORRS	R14,R14,#C_flag		;Set C initially
		STMFD	R13!,{R1,R2,R12,R14}	;Stack some registers
		WSPACE	template_wspace		;Find my workspace
		LDR	R2,template_list	;Find the list head

		; --- Go through the list trying to find one ---

00		CMP	R2,#0			;Is this the list end?
		BEQ	%10tpl__find		;Yes -- return the error
		ADD	R1,R2,#tlist_name	;Find this template's name
		BL	str_icmp		;Compare the names
		LDRNE	R2,[R2,#tlist_next]	;If no match, get next one...
		BNE	%b00			;And go round again

		; --- We found a match!!! ---

		MOV	R0,R2			;Point to the template
		LDMFD	R13!,{R1,R2,R12,R14}	;Unstack some registers
		BICS	PC,R14,#V_flag		;Return with no error

		; --- No match -- try shared resource ---

10tpl__find	MOV	R1,R0			;Point to the template name
		MOV	R0,#rsType_template	;Search for template resource
		BL	resources_find		;Try to find the resource
		LDMCSFD	R13!,{R1,R2,R12,R14}	;If it worked, get registers
		BICCSS	PC,R14,#C_flag + V_flag	;And return with no error

		; --- Couldn't find it then ---

20tpl__find	MOV	R2,R1			;Point to the template name
		ADR	R0,tpl__notfound	;Point to error message
		BL	msgs_error		;Translate the message
		LDMFD	R13!,{R1,R2,R12,R14}	;Unstack some registers
		ORRS	PC,R14,#V_flag		;Return with the error

tpl__notfound	DCD	1
		DCB	"tplTNF",0

		LTORG

; --- template_find ---
;
; On entry:	R0 == pointer to name to match
;
; On exit:	R0 == pointer to window definition if found
;		May return an error
;
; Use:		Locates a template in the list and gives you a pointer to
;		the corresponding window defintion.  You may update the
;		definition to store an updated window state if you really
;		want to.
;
;		Note that this call will fail if you attempt to find a
;		template which is held in the shared resources DLL.

		EXPORT	template_find
template_find	ROUT

		STMFD	R13!,{R1,R2,R14}	;Save return address
		MOV	R2,R0			;Remember the name
		BL	tpl__find		;Find the definition
		BVS	%10template_find	;If failed, skip onwards
		BCC	%05template_find	;If in resource DLL, skip
		ADD	R0,R0,#tlist_size	;Point to window def
		LDMFD	R13!,{R1,R2,R14}	;Return to caller
		BICS	PC,R14,#V_flag

		; --- It's in the resources DLL ---

05template_find	ADR	R0,tpl__notfound	;Point to error message
		BL	msgs_error		;Translate the message

		; --- Couldn't find the template ---

10template_find	LDMFD	R13!,{R1,R2,R14}	;Restore registers
		ORRS	PC,R14,#V_flag		;And return the error

		LTORG

; --- template_copy ---
;
; On entry:	R0 == pointer to name to match
;
; On exit:	R0 == pointer to copy of a window definition
;		May return an error
;
; Use:		Returns a copy of a window template (for the use of the
;		dialogue box system mainly), including all indirected data
;		set up properly and everything.  The copy is writable.  To
;		get rid of the copy, call template_free.

		EXPORT	template_copy
template_copy	ROUT

		; --- Find the copy first ---

		STMFD	R13!,{R1-R5,R14}	;Save some registers
		BL	tpl__find		;Find the definition
		BVS	%99template_copy	;If it failed, tidy up
		BCC	%50template_copy	;In resources -- handle it
		MOV	R5,R0			;Keep pointer to definition

		; --- Now allocate the memory we need ---

		LDR	R0,[R5,#84+tlist_size]	;Get the number of icons
		MOV	R0,R0,LSL #5		;Multiply by 32 for size
		ADD	R0,R0,#88+tlist_size	;Bump up by overhead
		MOV	R2,R0			;Keep the size safe
		BL	alloc			;Allocate the memory
		BCS	%98template_copy	;If that failed, skip ahead
		MOV	R4,R0			;Keep that pointer safe

		; --- Copy the window defintion over ---

		MOV	R1,R5			;Point to the definition
		MOV	R0,R4			;And my new block
		BL	fastMove		;Copy that data across

		; --- Now see if we need do anything else

		LDR	R0,[R5,#tlist_indsize]	;Get indirected data size
		CMP	R0,#0			;Is there any?
		BEQ	%10template_copy	;If not, skip past this bit

		; --- Allocate the indirected space ---

		MOV	R2,R0			;Look after the size
		BL	alloc			;Allocate the new block
		BCS	%97template_copy	;And tidy up if it failed

		; --- Copy indirected data over ---

		LDR	R1,[R5,#tlist_indptr]	;Find the old indirect block
		BL	fastMove		;Copy it over very quickly
		STR	R0,[R4,#tlist_indptr]	;Store the new block pointer

		; --- Now fix up all the references ---

		SUB	R5,R0,R1		;Get the relocation offset
		LDR	R0,[R4,#56+tlist_size]	;Get the title bar flags
		ADD	R1,R4,#72+tlist_size	;Point to the title data
		BL	tpl__fixData		;Fix up that data

		LDR	R3,[R4,#84+tlist_size]	;Get the number of icons
		ADD	R2,R4,#88+tlist_size	;Point to the first icon
00template_copy	SUBS	R3,R3,#1		;Decrement the icon counter
		LDRGE	R0,[R2,#16]		;Get the icon flags word
		ADDGE	R1,R2,#20		;Point to the icon data
		BLGE	tpl__fixData		;And fix up the icon data
		ADDGE	R2,R2,#32		;Move onto the next icon
		BGE	%00template_copy	;And move onto the next one

		; --- All done -- return the pointer ---

10template_copy	ADD	R0,R4,#tlist_size	;Point to the actual defn
		LDMFD	R13!,{R1-R5,R14}	;Unstack a load of registers
		BICS	PC,R14,#V_flag		;Return to caller

		; --- It's in the resources DLL ---

50template_copy	LDMFD	R13!,{R1-R5,R14}	;Restore these registers
		B	template_embedded	;Extract embedded definition

		; --- Error -- free the template block ---

97template_copy	MOV	R0,R4			;Point to the template block
		BL	free			;Free up the block

		; --- Return the error ---

98template_copy	BL	alloc_error		;Find the correct error mesg

99template_copy	LDMFD	R13!,{R1-R5,R14}	;Restore the registers
		ORRS	PC,R14,#V_flag		;Return to caller

		LTORG

; --- tpl__fixData ---
;
; On entry:	R0 == icon flags
;		R1 == pointer to icon data to fix
;		R5 == offset to bodge data by
;
; On exit:	Registers preserved
;
; Use:		Relocates indirected data by a given amount

tpl__fixData	ROUT

		TST	R0,#&00000100		;Is it indirected?
		MOVEQS	PC,R14			;No -- return right now

		; --- Fix up icon data ---

		STMFD	R13!,{R14}		;Save the link register
		LDR	R14,[R1,#0]		;Get the data pointer
		ADD	R14,R14,R5		;Relocate it
		STR	R14,[R1,#0]		;And store it back again

		; --- Is there validation data too? ---

		TST	R0,#&00000001		;Does it contain text data?
		LDRNE	R14,[R1,#4]		;Yes -- get validation ptr
		CMPNE	R14,#-1			;If the pointer sensible?
		LDMEQFD	R13!,{PC}^		;No -- return

		; --- Relocate validation string pointer ---

		ADD	R14,R14,R5		;Relocate it
		STR	R14,[R1,#4]		;Store it back in the block
		LDMFD	R13!,{PC}^		;Return to caller

		LTORG

; --- template_embedded ---
;
; On entry:	R0 == pointer to embedded template definition
;
; On exit:	R0 == pointer to copy (as for template_copy)
;
; Use:		Extracts an embedded template into a template block.
;		Embedded templates can be generated using the templAOF
;		program, and then linked into your application.

		EXPORT	template_embedded
template_embedded ROUT

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

		; --- First load the header out ---

		LDMIA	R0,{R3-R5}		;Load the three pointers out
		ADD	R3,R3,R0		;Relocate the window pointer
		ADD	R4,R4,R0		;Relocate the ind base ptr
		ADD	R5,R5,R0		;Relocate the ind limit ptr
		ADD	R6,R0,#12		;And find the relocation tbl

		; --- Allocate a block for the window definition ---

		LDR	R14,[R3,#84]		;Load the number of icons
		MOV	R0,#88+tlist_size	;Get the base memory req
		ADD	R0,R0,R14,LSL #5	;Add space for the icons
		SUB	R2,R0,#tlist_size	;Keep size without extras
		BL	alloc			;Try to allocate the space
		BLCS	alloc_error		;If it failed, get error
		BCS	%99template_embedded	;And skip onwards
		MOV	R7,R0			;Look after this pointer

		; --- Copy the window data over ---

		ADD	R0,R7,#tlist_size	;Point to window def area
		MOV	R1,R3			;Point to the original def
		BL	fastMove		;Copy that over

		; --- Now handle the data ---

		SUBS	R0,R5,R4		;Find indirected data size
		STR	R0,[R7,#tlist_indsize]	;Store the size away
		STREQ	R0,[R7,#tlist_indptr]	;If none, store null ptr
		BEQ	%10template_embedded	;And skip on to relocate

		BL	alloc			;Allocate the space
		BLCS	alloc_error		;If it failed, get error
		BCS	%98template_embedded	;And skip onwards
		STR	R0,[R7,#tlist_indptr]	;Store the pointer

		; --- Copy the data over ---

		MOV	R1,R4			;Point to original data
		SUB	R2,R5,R4		;Find the data size
		BL	fastMove		;Copy it over nicely

		; --- Finally do the relocation ---

10		MOV	R5,R0			;Look after indirected addr
		BL	resspr_area		;Find the sprite area
		MOV	R4,R0			;Look after that too
		ADD	R0,R7,#tlist_size	;Find window definition

00		CMP	R6,R3			;Finished yet?
		BCS	%90template_embedded	;Yes -- wrap things up
		LDR	R14,[R6],#4		;Load next directive
		MOV	R2,R14,LSR #28		;Get the directive type
		BIC	R14,R14,#&F0000000	;And the offset
		ADD	PC,PC,R2,LSL #2		;Dispatch to handler
		DCB	"MDW!"
		B	%15template_embedded
		B	%20template_embedded
		B	%b00

15		LDR	R2,[R0,R14]		;Load the word
		ADD	R2,R2,R5		;Relocate for indirectedness
		STR	R2,[R0,R14]		;Store it back again
		B	%b00			;Loop

20		STR	R4,[R0,R14]		;Store the sprite area
		B	%b00			;Loop

		; --- Finished -- return ---

90		LDMFD	R13!,{R1-R7,R14}	;Load lots of registers
		BICS	PC,R14,#V_flag		;And return errorless

		; --- Errors -- tidy up ---

98		MOV	R6,R0			;Look after error pointer
		MOV	R0,R7			;Get the template block
		BL	free			;Free it
		MOV	R0,R6			;Restore error pointer

99		LDMFD	R13!,{R1-R7,R14}	;Load lots of registers
		ORRS	PC,R14,#V_flag		;And return the error

		LTORG

; --- template_free ---
;
; On entry:	R0 == pointer to block allocated with template_copy
;
; On exit:	--
;
; Use:		Frees a template copy created using template_copy.

		EXPORT	template_free
template_free	ROUT

		STMFD	R13!,{R0,R1,R14}	;Save some registers
		SUB	R1,R0,#tlist_size	;Find base of block
		LDR	R0,[R1,#tlist_indptr]	;Get indirect data pointer
		CMP	R0,#0			;Is there any indirect data?
		BLNE	free			;Yes -- free the memory
		MOV	R0,R1			;Get the block pointer
		BL	free			;Free that too
		LDMFD	R13!,{R0,R1,PC}^	;Return to caller

		LTORG

; --- template_load ---
;
; On entry:	R0 == pointer to name of template file to load
;
; On exit:	May return an error
;
; Use:		Loads the specified template file, and adds its window
;		definitions into the template list so they can be used when
;		creating dialogue boxes or windows.
;
;		If the templates can't be loaded (e.g. there isn't enough
;		memory) an error is generated (and can be caught using the
;		standard Sapphire except mechanism).

		EXPORT	template_load
template_load	ROUT

		; --- We need a lot of registers! ---

		STMFD	R13!,{R0-R12,R14}	;Save the registers we want
		WSPACE	template_wspace		;Find my workspace

		; --- Find out how big the file is ---

		MOV	R1,R0			;Point to the filename
		MOV	R0,#17			;Info about file please
		SWI	XOS_File		;Try to load the file
		BVS	%99template_load	;If no luck, make the error

		; --- Allocate a heap block for it ---

		MOV	R0,R4			;Get the template file size
		BL	alloc			;Allocate the block
		BLCS	alloc_error		;If it failed, get error
		BCS	%99template_load	;If no luck, make the error
		MOV	R8,R0			;Guard pointer with life :-)

		; --- Load template file into buffer ---

		MOV	R0,#16			;Load a file into memory
		LDR	R1,[R13,#0]		;Get the filename back
		MOV	R2,R8			;Point to my buffer
		MOV	R3,#0			;Load into my buffer
		SWI	XOS_File		;Load the file now
		BVS	%98template_load	;Bad news -- free block first

		; --- Now we can parse the file up ---

		ADD	R10,R8,#16		;Find the first index entry
00template_load	LDR	R0,[R10,#0]		;Is this an empty entry?
		CMP	R0,#0			;Just check quickly
		BEQ	%05template_load	;Yes -- we've finished

		ADD	R9,R8,R0		;Point to the actual entry

		LDR	R1,[R10,#8]		;Get the entry type number
		SUB	R1,R1,#1		;Convert it to zero-indexed
		CMP	R1,#(%11-%10)/4		;Make sure it's recognised
		BCS	%02template_load	;No -- don't to it then
		STMFD	R13!,{R8,R12}		;Save workspace and base
		MOV	R12,R13			;Point to this pair
		MOV	R14,PC			;Set up return address
		ADD	PC,PC,R1,LSL #2		;Branch table dispatch
		B	%01template_load	;And link in the block

10template_load	B	tpl__loadWind		;Load a window definition
11template_load

01template_load	LDMFD	R13!,{R8,R12}		;Find workspace too
		BVS	%98template_load	;It failed miserably

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

		LDR	R1,template_list	;Find the list head
		STR	R1,[R0,#tlist_next]	;Make it this one's next ptr
		STR	R0,template_list	;And make this the list head

		; --- Move on to the next entry ---

02template_load	ADD	R10,R10,#24		;Move to the next entry
		B	%00template_load	;And go back again

		; --- We finished loading the file -- free buffer ---

05template_load	MOV	R0,R8			;Point to the file buffer
		BL	free			;Free the memory now

		; --- Now we can leave ---

		LDMFD	R13!,{R0-R12,R14}	;Return to caller
		BICS	PC,R14,#V_flag

		; --- Error encountered after block allocation ---

98template_load	MOV	R9,R0			;Keep error pointer
		MOV	R0,R8			;Point to the file buffer
		BL	free			;Free the memory now
		MOV	R0,R9			;Restore error pointer

		; --- Error encountered before block allocation ---

99template_load	ADD	R2,R0,#4		;Point to error message
		ADR	R0,tload__error		;Point to error skeleton
		BL	msgs_error		;Create the error message
		ADD	R13,R13,#4		;Skip past stacked R0
		LDMFD	R13!,{R1-R12,R14}	;Return to caller
		ORRS	PC,R14,#V_flag		;With error indicator set

tload__error	DCD	1
		DCB	"tplTLE",0

		LTORG

template_wspace	DCD	0

; --- template_init ---
;
; On entry:	R0 == pointer to application name
;
; On exit:	--
;
; Use:		Initialises the template list and font array, and loads the
;		`Templates' resource file.

		EXPORT	template_init
template_init	ROUT

		STMFD	R13!,{R0,R1,R12,R14}	;Store some registers
		WSPACE	template_wspace		;Find my workspace
		LDR	R14,template_list	;Get the current list
		CMP	R14,#0			;Is it silly?
		LDMNEFD	R13!,{R0,R1,R12,PC}^	;No -- we're already running

		BL	alloc_init		;Make sure we can find memory
		BL	resspr_init		;This will initialise res too
		BL	except_init		;For atexit to tidy up later

		; --- Set up the workspace nicely ---

		MOV	R0,#0			;Store null pointers
		STR	R0,template_list	;No templates yet
		STR	R0,template_fonts	;No fonts found either

		; --- Build the name in the scratchpad ---

		ADR	R0,tpl__templates	;Point to the resource name
		MOV	R1,R11			;Point to scratchpad buffer
		ADDS	R0,R0,#0		;Clear C and V flags
		BL	res_find		;Find the resource file

		; --- Load the file and return ---

		BLCS	template_load		;Load the file if it's there
		SWIVS	OS_GenerateError	;If it failed, make an error
		LDMFD	R13!,{R0,R1,R12,PC}^	;Return to the caller

tpl__templates	DCB	"Templates",0

		LTORG

; --- tpl__killFont ---
;
; On entry:	R12 == pointer to template workspace
;
; On exit:	--
;
; Use:		Loses loads of fonts when the application quits

tpl__killFont	ROUT

		STMFD	R13!,{R0-R2,R14}	;Save some registers
		LDR	R1,template_fonts	;Find the font array
		MOV	R0,#255			;Start at the top for this
00tpl__killFont	LDRB	R2,[R1,R0]		;Get the reference counter
01tpl__killFont	SUBS	R2,R2,#1		;Decrement the counter
		SWIGE	Font_LoseFont		;Lose the font
		BGE	%01tpl__killFont	;And go round again
		SUBS	R0,R0,#1		;Decrement the handle
		BGE	%00tpl__killFont	;And go round again
		LDMFD	R13!,{R0-R2,PC}^	;And return to caller

		LTORG

;----- Template loading routines --------------------------------------------
;
; For all routines:
;
; On entry:	R9 == pointer to entry in memory
;		R10 == pointer to index entry for this object
;		R12 == pointer to template base and workspace block
;
; On exit:	If successful:
;		  R0 == pointer to template entry to add into the list
;		  V flag clear
;		If an error occurred:
;		  R0 == pointer to standard error block
;		  V flag set
;		R1-R9 may be corrupted

; --- tpl__loadWind ---
;
; Use:		Loads a window definition and converts it into a template
;		list item

tpl__loadWind	ROUT

		STMFD	R13!,{R14}		;Just stack the return addr

		; --- Find out how many icons there are ---

		ADD	R0,R9,#84		;Point to the right place
		AND	R1,R0,#3		;Get the non-word-alignedness
		BIC	R0,R0,#3		;And round down to word
		LDMIA	R0,{R2,R3}		;Get the two words we want
		MOV	R1,R1,LSL #3		;Turn bytes into bits
		MOV	R8,R2,LSR R1		;Get the bottom few bytes
		RSB	R1,R1,#32		;Get the shift the other way
		ORR	R8,R8,R3,LSL R1		;And copy in the top bytes

		; --- R8 now contains the number of icons ---

		; --- Allocate a template block ---

		MOV	R3,R8,LSL #5		;Multiply the number by 32
		ADD	R3,R3,#88+tlist_size	;Add on window and list block
		MOV	R0,R3			;I want to allocate memory
		BL	alloc			;Allocate the space
		BLCS	alloc_error		;If it failed, get error
		BCS	%99tpl__loadWind	;If it failed, return error
		MOV	R7,R0			;Keep the pointer

		; --- Copy the window definition into the block ---

		ADD	R0,R7,#tlist_size	;Where to store definition
		SUB	R2,R3,#tlist_size	;Size of block to copy
		MOV	R1,R9			;Point to the window def
		BL	fastMove		;And shunt the bytes over

		; --- We may as well copy the name over now too ---

		ADD	R1,R10,#12		;Point to the template name
		ADD	R0,R7,#tlist_name	;Point to my block section
		LDMIA	R1,{R2-R4}		;Get the twelve bytes
		STMIA	R0,{R2-R4}		;Store them in my block
		MOV	R1,#0			;And zero terminate
		STRB	R1,[R0,#12]		;Stop the string off nicely

		; --- Widge the sprite area ---

		BL	resspr_area		;Load the sprite area ptr
		STR	R0,[R7,#64+tlist_size]	;Store sprite area pointer

		; --- Now count the amount of indirected data ---

		MOV	R6,#0			;Currently no indirected size

		LDR	R5,[R7,#56+tlist_size]	;Get the title bar flags
		ADD	R4,R7,#72+tlist_size	;Point to the title bar data
		BL	tpl__dataSize		;Add in the space required

		MOV	R0,R8			;The number of icons I have
		ADD	R1,R7,#88+tlist_size	;Point to the first icon
00tpl__loadWind	SUBS	R0,R0,#1		;Decrement the counter
		LDRGE	R5,[R1,#16]		;Get the flags word here
		ADDGE	R4,R1,#20		;Point to the icon data
		BLGE	tpl__dataSize		;Add in the extra data
		ADDGE	R1,R1,#32		;Point to the next icon defn
		BGE	%00tpl__loadWind	;And go back for the rest

		; --- We now have the data size in R6 ---

		STR	R6,[R7,#tlist_indsize]	;Store the buffer size away
		CMP	R6,#0			;Is there any indirect space?
		STREQ	R6,[R7,#tlist_indptr]	;No -- store a null pointer
		BEQ	%01tpl__loadWind	;... and skip past allocation

		; --- Allocate the buffer properly ---

		MOV	R0,R6			;Get the size of the block
		BL	alloc			;Allocate yet more memory
		BLCS	alloc_error		;If failed, get error
		BCS	%98tpl__loadWind	;If it failed, report error
		MOV	R6,R0			;Point to the new buffer
		STR	R6,[R7,#tlist_indptr]	;Save indirected size away

		; --- Now copy the indirected data across ---
		;
		; We also fix up the pointers at the same time, and set up
		; any fonts that need loading.

01tpl__loadWind	LDR	R5,[R7,#56+tlist_size]	;Get the title bar flags
		ADD	R4,R7,#72+tlist_size	;Point to the title bar data
		BL	tpl__copyData		;Process the indirect data
		ADD	R5,R7,#56+tlist_size	;Point to the flags now
		BL	tpl__findFont		;And handle any fonts
		BVS	%97tpl__loadWind	;Quit if something went wrong

		MOV	R0,R8			;The number of icons I have
		ADD	R1,R7,#88+tlist_size	;Point to the first icon
02tpl__loadWind	SUBS	R0,R0,#1		;Decrement the counter
		BLT	%03tpl__loadWind	;If no more, skip ahead
		LDR	R5,[R1,#16]		;Get the flags word here
		ADD	R4,R1,#20		;Point to the icon data
		BL	tpl__copyData		;Copy over the indirect data
		ADD	R5,R1,#16		;Point to the flags now
		BL	tpl__findFont		;And handle any fonts
		BVS	%97tpl__loadWind	;Quit if something went wrong
		ADD	R1,R1,#32		;Point to the next icon defn
		B	%02tpl__loadWind	;Now go back for the rest

		; --- The excitement's over now, so that's it ---

03tpl__loadWind	MOV	R0,R7			;Point at the template block
		LDMFD	R13!,{R14}		;Get the link register out
		BICS	PC,R14,#V_flag		;And return no errors

		; --- Something screwed up -- deallocate both blocks ---

97tpl__loadWind	MOV	R9,R0			;Save error pointer
		LDR	R0,[R7,#tlist_indptr]	;Find the indirect block addr
		BL	free			;Free indirect data block
		MOV	R0,R9			;Restore error pointer

		; --- Error occurred -- free the template block ---

98tpl__loadWind	MOV	R9,R0			;Save error pointer
		MOV	R0,R7			;Point to template block
		BL	free			;Free the template block
		MOV	R0,R9			;Restore error pointer

		; --- Error occurred -- return with V set ---

99tpl__loadWind	LDMFD	R13!,{R14}		;Get the link register
		ORRS	PC,R14,#V_flag		;Set the error indicator

		LTORG

;----- Support functions ----------------------------------------------------

; --- tpl__dataSize ---
;
; On entry:	R4 == pointer to icon data
;		R5 == icon flags word
;		R6 == counter to increment
;		R7 == pointer to window block
;		R8 == number of icons in the window
;		R9 == pointer to the window definition in the template file
;		R10 == pointer to index for current window
;		R12 == pointer to template base and workspace block
;
; On exit:	R6 incremented by an appropriate amount
;		Everything else preserved (except R14, obviously!)
;
; Use:		Counts the amount of indirected space required for a given
;		icon flags/data pair and adds it into a running total

tpl__dataSize	ROUT

		; --- Make sure there's something to do ---

		TST	R5,#&00000100		;Test indirected bit
		MOVEQS	PC,R14			;If not indirected, go away

		; --- Locate and count the indirected data string ---

		STMFD	R13!,{R14}		;Save some registers
		LDR	R14,[R4,#8]		;Get the indirect buffer size
		ADD	R6,R6,R14		;And add this onto the count

		; --- Check if there's a validation string ---

		TST	R5,#&00000001		;Is the `Is text' bit on?
		LDRNE	R14,[R4,#4]		;Yes -- get validation ptr
		CMPNE	R14,#-1			;Is it a sensible pointer?
		LDMEQFD	R13!,{PC}^		;If not, we're done for now

		; --- Count length of validation string ---

		STMFD	R13!,{R0}		;Save another register
		ADD	R0,R14,R9		;Point to string in memory
		BL	str_len			;Find its length
		ADD	R0,R0,#1		;Account for the terminator
		ADD	R6,R6,R0		;Add this to the counter
		LDMFD	R13!,{R0,PC}^		;And return to the caller

		LTORG

; --- tpl__copyData ---
;
; On entry:	R4 == pointer to icon data
;		R5 == icon flags word
;		R6 == pointer to free part of buffer
;		R7 == pointer to window block
;		R8 == number of icons in the window
;		R9 == pointer to the window definition in the template file
;		R10 == pointer to index for current window
;		R12 == pointer to template base and workspace block
;
; On exit:	R6 incremented by an appropriate amount
;		Everything else preserved (except R14, obviously!)
;
; Use:		Copies indirected data from an icon definition into the
;		buffer given and fixes up pointers in the definition

tpl__copyData	ROUT

		; --- Make sure there's something to do here ---

		TST	R5,#&00000100		;Check the indirected bit
		MOVEQS	PC,R14			;If unset, return right now

		; --- Handle basic indirected data ---

		STMFD	R13!,{R0,R1,R14}	;Stack some registers
		LDR	R1,[R4,#0]		;Get the indirected pointer
		STR	R6,[R4,#0]		;Store the new pointer in
		ADD	R1,R9,R1		;Offset by window address
		MOV	R0,R6			;Point to free bit of bufffer
		BL	str_cpy			;Copy (and null-terminate)
		LDR	R14,[R4,#8]		;Get the indirect buffer size
		ADD	R6,R6,R14		;Move buffer pointer on by it

		; --- Check for validation string presence ---

		TST	R5,#&00000001		;Is the `Is text' bit on?
		LDRNE	R14,[R4,#4]		;Yes -- get validation ptr
		CMPNE	R14,#-1			;Is it a sensible pointer?
		LDMEQFD	R13!,{R0,R1,PC}^	;If not, we're done

		; --- Handle the validation string ---

		STR	R6,[R4,#4]		;Store the new pointer
		ADD	R1,R9,R14		;Point to the validation str
		MOV	R0,R6			;Point to the bit of buffer
		BL	str_cpy			;And copy the string across
		ADD	R6,R0,#1		;Point R6 past string term
		LDMFD	R13!,{R0,R1,PC}^	;That's it from us, then

		LTORG

; --- tpl__findFont ---
;
; On entry:	R5 == pointer to icon flags word
;		R6 == pointer to free part of buffer
;		R7 == pointer to window block
;		R8 == number of icons in the window
;		R9 == pointer to the window definition in the template file
;		R10 == pointer to index for current window
;		R12 == pointer to template base and workspace block
;
; On exit:	Everything preserved except R4 (and R14, obviously!)
;
; Use:		Fixes up an icon's anti-aliased font data.

tpl__findFont	ROUT

		LDR	R4,[R5]			;Get the icon flags word
		TST	R4,#&00000040		;Is it antialiased?
		TSTNE	R4,#&00000001		;Make sure it's text too
		BICEQS	PC,R14,#V_flag		;If not, return no error

		; --- Now to business -- ensure we have a font table ---

		STMFD	R13!,{R0-R3,R5,R12,R14}	;Save some registers
		LDMIA	R12,{R5,R12}		;Load base and workspace
		LDR	R0,template_fonts	;Find font array pointer
		CMP	R0,#0			;Is it null?
		BEQ	%00tpl__findFont	;Yes -- allocate it

		; --- Now locate the font table in the file ---

01tpl__findFont	LDR	R3,[R5,#0]		;Get the font table offset
		ADD	R3,R5,R3		;Convert it to a pointer

		; --- Find internal font handle and get table entry ---

		MOV	R0,R4,LSR #24		;Leave only the font handle
		SUB	R0,R0,#1		;Convert to 0-indexed
		STMFD	R13!,{R4,R5}		;Need some more registers!!
		ADD	R4,R3,R0,LSL #4		;R4 = R3 + R0 * 16
		ADD	R4,R4,R0,LSL #5		;Now R4 = R3 + R0 * 48

		; --- Now we must load the font width and height ---
		;
		; The problem is that they're not on word boundaries, so
		; we must do clever-dick things with the barrel shifter.

		AND	R0,R3,#3		;Get the bottom two bits
		BIC	R1,R3,#3		;Word align the base address
		LDMIA	R1,{R2,R3,R14}		;Get the width and height
		MOV	R0,R0,LSL #3		;Convert bits to bytes
		RSB	R1,R0,#32		;Get the other shift too
		MOV	R2,R2,LSR R0		;Shift the bits down here
		ORR	R2,R2,R3,LSL R1		;And add in the top bits
		MOV	R3,R3,LSR R0		;Shift down bottom bits
		ORR	R3,R3,R14,LSL R1	;And add in the top bits

		; --- We are now in a position to find the font ---

		ADD	R1,R4,#8		;Point to the font name
		MOV	R4,#0			;Default x scaling
		MOV	R5,#0			;Default y scaling
		SWI	Font_FindFont		;Try very hard to find it
		LDMFD	R13!,{R4,R5}		;Restore these registers
		ADDVS	R13,R13,#4		;If it failed, skip R0,
		LDMVSFD	R13!,{R1-R3,PC}		;... and restore regs

		; --- Now bump the item in the font array ---

		LDR	R1,template_fonts	;Find the font array
		LDRB	R2,[R1,R0]		;Get counter for the handle
		ADD	R2,R2,#1		;Bump the counter a bit
		STRB	R2,[R1,R0]		;And store it away again

		; --- Bodge the icon flags word for the new handle ---

		BIC	R4,R4,#&FF000000	;Clear out the old handle
		ORR	R4,R4,R0,LSL #24	;Bring in the new...
		STR	R4,[R5]			;Store the new flags word
		LDMFD	R13!,{R0-R3,R5,R12,R14}	;Restore the registers
		BICS	PC,R14,#V_flag		;And return with no error

		; --- Create the font array if it's not there ---

00tpl__findFont	MOV	R0,#256			;One byte for each font
		BL	alloc			;Allocate the memory
		BLCS	alloc_error		;If failed, get error
		ADDCS	R13,R13,#4		;If it failed, bump R13
		LDMCSFD	R13!,{R1-R3,R5,R12,PC}	;... and return with error
		STR	R0,template_fonts	;Store the new pointer

		; --- Clear the font array to 0s ---

		MOV	R1,#256			;The size of the array
		MOV	R2,#0			;Value to initialise with
		BL	mem_set			;Clear out the array

		; --- Register our tidy-up routine ---

		ADR	R0,tpl__killFont	;Point to tidy up function
		MOV	R1,R12			;Point to my workspace
		BL	except_atExit		;Register it properly
		B	%01tpl__findFont	;Return to the main proc

		LTORG

;----- The list structure ---------------------------------------------------

		^	0
tlist_start	#	0

tlist_next	#	4			;Pointer to the next one
tlist_name	#	16			;Name of this template
tlist_indptr	#	4			;Pointer to indirect data
tlist_indsize	#	4			;Size of indirect data
; Window definition follows

tlist_size	#	0			;Size of that structure

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

		^	0,R12
template_wstart	#	0

template_list	#	4			;List head for templates
template_fonts	#	4			;Font array if we need one

template_wsize	EQU	{VAR}-template_wstart

		AREA	|Sapphire$$LibData|,CODE,READONLY

		DCD	template_wsize
		DCD	template_wspace
		DCD	256
		DCD	template_init

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

		END
