;
; ibicon.s
;
; Icon bar icon handling (TMA)
;
;  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:msgs
		GET	sapphire:suballoc
		GET	sapphire:sapphire
		GET	sapphire:string
		GET	sapphire:resspr
		GET	sapphire:wimp
		GET	sapphire:win

;----- Event types ----------------------------------------------------------

		^	0
ibEvent_select	#	1
ibEvent_menu	#	1
ibEvent_adjust	#	1
ibEvent_save	#	1
ibEvent_load	#	1
ibEvent_help	#	1

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

		AREA	|Sapphire$$Code|,CODE,READONLY

; --- ibicon__addToList ---
;
; On entry:	R0 == icon handle
;		R1 == pointer to routine to call
;		R2 == pointer to icon data
;		R3 == pointer to validation string
;		R4 == R10 value to call routine
;		R5 == R12 value to call routine with
;		R6 == pointer to list head to use
;
; On exit:	R0-R6 preserved
;
; Use:		Adds a rountine to the given list. Later added
;		routines are called first

ibicon__addToList
		ROUT

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

		; --- Allocate a block ---

		MOV	R0,#list__size		;Size to allocate
		BL	sub_alloc		;Allocate the block
		BVS	%01			;Branch ahead if error

		; --- Fill the block in ---

		LDR	R1,[R6]			;Get the list head
		STR	R1,[R0,#list__next]	;Store in next field
		STR	R0,[R6]			;Store new block at head

		LDMIA	R13,{R1-R6}		;Get parameters
		STMIB	R0,{R1-R6}		;Store them in the block

		; --- And return to user ---

		LDMFD	R13!,{R0-R6,R14}	;Load back link
		BICS	PC,R14,#V_flag		;Return without error

		; --- Barf if an error occured ---

01		ADD	R13,R13,#4		;Skip over R0
		LDMFD	R13!,{R1-R6,R14}	;Branch if error
		ORRS	PC,R14,#V_flag		;Return with error

		LTORG

; --- ibicon__removeFromList ---
;
; On entry:	R0 == ibicon pointer
;		R1 == pointer to list head to use
;
; On exit:	All registers/flags preserved
;
; Use:		Removes a routine from the given list. All values are
;		compared.

ibicon__removeFromList
		ROUT

		STMFD	R13!,{R0-R4,R14}

		; --- Find the block ---

		MOV	R2,R1			;The previous pointer
		LDR	R1,[R1]			;Get the head of the list
01		TEQ	R1,#0			;Are we at the end?
		LDMEQFD	R13!,{R0-R4,PC}^ 	;Yes -- return
		LDR	R4,[R1]			;Get the next pointer
		CMP	R1,R0			;Are pointers the same?
		MOVNE	R2,R1			;If no, remember previous
		MOVNE	R1,R4			;...get list pointer
		BNE	%01			;...and keep looking

		; --- So now the block has been found ---

		MOV	R0,R1			;Put the block in R0
		MOV	R1,#list__size		;Get the size
		BL	sub_free		;Free the block
		STR	R4,[R2,#0]		;Store in prev next ^

		; --- And return to the user ---

		LDMFD	R13!,{R0-R4,PC}^

		LTORG

; --- ibicon__size ---
;
; On entry:	R0 == pointer to block to use
;		R1 == sprite area to use
;		R2 == pointer to sprite name
;
; On exit:	--
;
; Use:		Determines the size of the given icon, and fills in the
;		block appropriatly (x0,y0,x1,y1)

ibicon__size	ROUT

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

		MOV	R0,#40			;Get sprite info
		CMP	R1,#1			;Is it WIMP area?
		ORRNE	R0,R0,#&100		;No -- use user area
		SWINE	XOS_SpriteOp		;...do the SpriteOp
		SWIEQ	Wimp_SpriteOp		;Yes, SpriteOp on WIMP area
		LDMVSFD	R13!,{R0-R6}		;Recover registers on error
		ORRVSS	PC,R14,#V_flag		;...and return with an error

		MOV	R0,R6			;Get info on sprite's mode
		MOV	R1,#4			;Read XEigFactor
		SWI	OS_ReadModeVariable	;Get the Eig Factor
		MOV	R3,R3,LSL R2		;Get the width in OS units
		MOV	R1,#5			;Read yEigFactor
		SWI	OS_ReadModeVariable	;Get the Eig Factor
		MOV	R4,R4,LSL R2		;Get the height in OS units
		MOV	R0,#0			;x0 coordinate
		MOV	R1,#0			;y0 coordinate
		LDR	R2,[R13,#0]		;Get the block to use
		STMIA	R2,{R0,R1,R3,R4}	;Store the size info

		LDMFD	R13!,{R0-R6}		;Recover registers
		MOVS	PC,R14			;And return

; --- ibicon_create ---
;
; On entry:	R0 == pointer to sprite name
;		R1 == pointer to text buffer (must be writable if you
;		      intend to change the text)
;		R2 == icon bar position indicator (`window handle')
;		R3 == icon bar priority/icon handle
;		R4 == pointer to event handler
;		R5 == value to pass in R10
;		R6 == value to pass in R12
;
; On exit:	R0 == ibicon icon handle
;		May return an error
;
; Use: 		Places an icon on the icon bar. Your handler is called when
;		an event occurs on the icon. On entry to the handler, R10
;		and R12 are set up as for above, R0 is the event type, and
;		R1 is the ibicon pointer.

		EXPORT	ibicon_create
ibicon_create	ROUT

		; --- Stack registers, locate workspace etc. ---

		STMFD	R13!,{R1-R7,R9,R10,R12,R14} ;Stack loads of registers
		WSPACE	ibicon__wSpace,R9	;Find a bit of workspace

		; --- Stuff useful values into high registers ---

		MOV	R12,R0			;Keep the sprite name safe
		MOV	R10,R1			;Keep the text pointer safe
		MOV	R7,R2			;Keep position thingy

		; --- Now create buffers for the sprite name ---

		MOV	R0,#16			;Size for sprite buffer
		BL	sub_alloc		;Get a block (PDQ)
		BVS	%99ibicon_create	;And zip ahead if it failed

		; --- Build the sprite name in the buffer ---

		MOV	R2,R0			;Keep the pointer for a while
		CMP	R10,#0			;Is there any text?
		MOVNE	R1,#'S'			;Yes -- stick an `S' on
		STRNEB	R1,[R0],#1		;And insert it at the front
		MOV	R1,R12			;Point to sprite name
		BL	str_cpy			;And build the name string
		MOV	R12,R2			;Keep this buffer pointer now

		; --- Build the icon definition ---

		SUB	R13,R13,#36		;Make space for the icon blk
		BEQ	%00ibicon_create	;If sprite only, deal with it

		; --- Deal with text+sprite icons ---

		MOV	R2,R1			;Point to original sname
		MOV	R1,#1			;Wimp sprite area
		ADD	R0,R13,#4		;Fill in this block
		BL	ibicon__size		;Get the sprite size

		LDR	R1,[R0,#4]		;Get y0
		SUB	R1,R1,#16		;y0=y0-16
		STR	R1,[R0,#4]		;Store adjusted y0
		LDR	R1,[R0,#12]		;Get y1
		ADD	R1,R1,#20		;y1=y1+20
		STR	R1,[R0,#12]		;Store adjusted y1

		STR	R10,[R13,#24]		;Store text buffer ^ if text
		STR	R12,[R13,#28]		;And the validation string ^
		MOV	R0,R10			;The text string
		BL	str_len			;How long is it?
		STR	R0,[R13,#32]		;Store the value
		LDR	R1,[R13,#12]		;Get the x1 icon size
		CMP	R1,R0,LSL#4		;Is it less than length*16
		MOVLT	R1,R0,LSL#4		;Yes, make it equal
		STRLT	R1,[R13,#12]		;...and store it back
		LDR	R0,=&1700312B		;The icon flags
		STR	R0,[R13,#20]		;Store them
		B	%01ibicon_create	;Jump ahead

		; --- Deal with sprite only icons ---

00ibicon_create	BL	resspr_area		;Get the sprite area to use
		STR	R0,[R13,#28]		;Store that in the block

		MOV	R10,R12			;R10 is icon data
		MOV	R12,#0			;No validation needed

		MOV	R1,R0			;Put sprite area in R1
		MOV	R2,R10			;Point to sprite name
		ADD	R0,R13,#4		;Fill in this block
		BL	ibicon__size		;Get the sprite size
		MOVVS	R1,#1			;If error -- try WIMP area
		BLVS	ibicon__size		;...try again
		STR	R10,[R13,#24]		;Store sprite name pointer
		MOV	R0,R10			;Point to sprite name
		BL	str_len			;Get its length
		STR	R0,[R13,#32]		;And store that too
		LDR	R0,=&1700311A		;The icon flags
		STR	R0,[R13,#20]		;Store them

		; --- Create the icon ---

01ibicon_create	BL	wimp_version		;Get the wimp version number
		LDR	R1,=310			;Wimp version
		MOV	R2,R7			;Get back position thingy
		CMP	R0,R1			;Is it less than RISC OS 3.1
		BGE	%02ibicon_create	;No -- go ahead

		; --- Ensure position word works on RISCOS 2/3.0 ---

		CMP	R2,#-5			;Left, scanning from left?
		CMPNE	R2,#-6			;Left, scanning from right?
		MOVEQ	R2,#-2			;Yes -- put it on left
		BEQ	%02ibicon_create	;Now go ahead

		CMP	R2,#-7			;Right, scanning from left?
		CMPNE	R2,#-8			;Right, scanning from right?
		MOVEQ	R2,#-1			;Yes -- put it on right

		; --- Actually create it ---

02ibicon_create	STR	R2,[R13,#0]		;The position to put icon in
		MOV	R0,R3			;Icon handle/priority
		MOV	R1,R13			;Point to the block
		SWI	XWimp_CreateIcon	;Create the icon
		ADD	R13,R13,#36		;Reclaim stack
		BVS	%99ibicon_create	;Barf if error

		; --- Add the icon into the list ---

		MOV	R2,R10			;Icon data
		MOV	R3,R12			;Validation string
		ADR	R6,ibicon__icons	;The head of the list
		ADD	R1,R13,#12		;Point to relevent parameters
		LDMIA	R1,{R1,R4,R5}		;Routine to call, R10, R12
		BL	ibicon__addToList	;Add to the list
		BVS	%99ibicon_create	;Stop if error occurred

		; --- Return to the user ---

		LDR	R0,ibicon__icons	;Return the ibicon pointer
		LDMFD	R13!,{R1-R7,R9,R10,R12,R14} ;Load my registers
		BICS	PC,R14,#V_flag		;Return without error

		; --- An error occurred ---

99ibicon_create	LDMFD	R13!,{R1-R7,R9,R10,R12,R14} ;Load my registers
		ORRS	PC,R14,#V_flag		;Return with error

		LTORG

; --- ibicon_changeSprite ---
;
; On entry:	R0 == ibicon pointer
;		R1 == pointer to sprite name
;
; On exit:	--
;
; Use:		Changes the sprite of the ibicon passed to it.

		EXPORT	ibicon_changeSprite
ibicon_changeSprite
		ROUT

		STMFD	R13!,{R0-R3,R9,R14}	;Stack some registers
		WSPACE	ibicon__wSpace,R9	;Get my workspace

		LDR	R3,[R0,#list__iHandle]	;Get the icon handle
		LDR	R2,[R0,#list__valid]	;Get the validation
		CMP	R2,#0			;Is there any?
		LDREQ	R0,[R0,#list__iData]	;No -- point to data
		ADDNE	R0,R2,#1		;Yes -- point passed the 'S'
		BL	str_cpy			;And copy the name across
		SUB	R13,R13,#16		;Get a block
		MOV	R0,#-2			;The icon bar
		MOV	R1,R3			;The icon handle
		MOV	R2,#0			;EOR Word
		MOV	R3,#0			;The clear word
		STMIA	R13,{R0-R3}		;Store in the block
		MOV	R1,R13			;Point to the block
		SWI	Wimp_SetIconState	;Update the icon
		ADD	R13,R13,#16		;Reclaim my stack
		LDMFD	R13!,{R0-R3,R9,PC}^	;Return to the user

		LTORG

; --- ibicon_changeText ---
;
; On entry:	R0 == ibicon pointer
;		R1 == pointer to new text
;
; On exit:	--
;
; Use:		Changes the sprite of the ibicon passed to it.

		EXPORT	ibicon_changeText
ibicon_changeText
		ROUT

		STMFD	R13!,{R0-R3,R9,R14}	;Stack some registers
		WSPACE	ibicon__wSpace,R9	;Get my workspace

		LDR	R3,[R0,#list__iHandle]	;Get the icon handle
		LDR	R2,[R0,#list__valid]	;Get the validation
		CMP	R2,#0			;Is there any?
		BEQ	%00			;No -- big time error
		LDR	R0,[R0,#list__iData]	;Point to the text buffer
		BL	str_cpy			;Copy the text across
		SUB	R13,R13,#16		;Get a block
		MOV	R0,#-2			;The icon bar
		MOV	R1,R3			;The icon handle
		MOV	R2,#0			;EOR Word
		MOV	R3,#0			;The clear word
		STMIA	R13,{R0-R3}		;Store in the block
		MOV	R1,R13			;Point to the block
		SWI	Wimp_SetIconState	;Update the icon
		ADD	R13,R13,#16		;Reclaim my stack
		LDMFD	R13!,{R0-R3,R9,PC}^	;Return to the user

		; --- We can't change the text of a sprite only icon ---

00		ADR	R0,ibicon__cantDo	;Point to the error message
		BL	msgs_error		;Translate the message
		SWI	OS_GenerateError	;Cause an error

ibicon__cantDo	DCD	0
		DCB	"ibCCT",0

		LTORG

; --- ibicon_remove ---
;
; On entry:	R0 == ibicon icon handle
;
; On exit:	--
;
; Use:		Removes the given icon from the icon bar.

		EXPORT	ibicon_remove
ibicon_remove	ROUT

		STMFD	R13!,{R0-R3,R9,R14}	;Stack some registers
		WSPACE	ibicon__wSpace,R9	;Locate my workspace

		; --- Delete the icon ---

		MOV	R2,R0			;Remember ibicon pointer
		SUB	R13,R13,#8		;Get a block
		LDR	R1,[R0,#list__iHandle]	;Get the icon handle
		MOV	R0,#-2			;The icon bar
		STMIA	R13,{R0,R1}		;Store handles in block
		MOV	R1,R13			;Point to block
		SWI	XWimp_DeleteIcon	;Delete the icon
		ADD	R13,R13,#8		;Reclaim the block from stack

		; --- Delete the ibicon data ---

		MOV	R0,R3			;Point to the ibicon
		LDR	R1,ibicon__icons	;Remove from this list
		BL	ibicon__removeFromList	;Remove the icon

		; --- And return from whence thy came ---

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

		LTORG

; --- ibicon__handler ---
;
; On entry:	R0 == event returned from Wimp_Poll
;		R1 == poll block
;		R12 == workspace
;
; On exit:	C set if call is claimed
;
; Use:		Called as an event handler when the wimp reports iconbar
;		activity

ibicon__handler	ROUT

		STMFD	R13!,{R0-R7,R9,R10,R14}	;Stack some registers
		MOV	R9,R12			;R9 is workspace pointer

		CMP	R0,#6			;Was it a button click
		BNE	%50			;No try messages
		LDR	R2,[R1,#8]		;Get buttons
		TST	R2,#1			;Was it Adjust
		MOVNE	R0,#ibEvent_adjust	;Yes -- set the type
		TST	R2,#4			;Was it select
		MOVNE	R0,#ibEvent_select	;Yes -- set the type
		TST	R2,#2			;Was it menu
		MOVNE	R0,#ibEvent_menu		;Yes -- set the type
		LDR	R1,[R1,#16]		;Get the icon handle

10		ADDS	R0,R0,#0		;Clear carry flag
		LDR	R2,ibicon__icons	;Get my icons list
20		TEQ	R2,#0			;Are we at the end
		BEQ	%30			;Yes -- jump ahead
		MOV	R7,R2			;Remember this pointer
		LDMIA	R2,{R2-R6,R10,R12}	;Load parameters to pass
		TEQ	R1,R3			;Are icon handles the same
		BNE	%20			;No -- try another handler
		TEQ	R4,#0			;Is there a handler?
		BEQ	%20			;No -- keep trying
		MOV	R1,R7			;Pass the pointer
		MOV	R14,PC			;Set return address
		MOV	PC,R4			;Branch to handler
		BCC	%20			;Try next handler
30		LDMFD	R13!,{R0-R7,R9,R10,R14}	;Load the registers
		BICCCS	PC,R14,#C_flag		;Return with carry clear
		ORRCSS	PC,R14,#C_flag		;... or with carry set

		; --- Was the event a suitable message ---

50		CMP	R0,#17			;User_Message
		CMPNE	R0,#18			;User_Message_Recorded
		LDMNEFD	R13!,{R0-R7,R9,R10,R14}	;No -- load the registers
		BICNES	PC,R14,#C_flag		;...and return with C clear

		MOV	R3,R1			;We need R1
		MOV	R0,#-1			;No type yet
		LDR	R2,[R3,#16]		;Get the message type
		CMP	R2,#1			;Data Save
		MOVEQ	R0,#ibEvent_save	;Yes -- set the type
		LDREQ	R1,[R3,#24]		;...and get the icon handle
		CMP	R2,#3			;Data Load
		MOVEQ	R0,#ibEvent_load	;Yes -- set the type
		LDREQ	R1,[R3,#24]		;...and get the icon handle
		LDR	R4,=&502		;Help request
		CMP	R2,R4			;Is it?
		MOVEQ	R0,#ibEvent_help	;Yes -- set the type
		LDREQ	R1,[R3,#36]		;...and get the icon handle

		CMP	R0,#-1			;Was the message valid
		BNE	%10			;Yes -- dispatch the event
		LDMEQFD	R13!,{R0-R7,R9,R10,R14}	;No -- load the registers
		BICEQS	PC,R14,#C_flag		;...and return with C clear

		LTORG

; --- ibicon_init ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Initialises the ibicon unit.

		EXPORT	ibicon_init
ibicon_init	ROUT

		STMFD	R13!,{R0-R3,R9,R14}	;Stack some registers
		WSPACE	ibicon__wSpace,R9	;Locate my workspace

		; --- Are we already initialised? ---

		LDR	R0,ibicon__flags	;Get my flags
		TST	R0,#ibicon__INITED	;Are we initialised?
		LDMNEFD	R13!,{R0,R9,PC}^	;Yes -- return

		ORR	R0,R0,#ibicon__INITED	;Set initialised flag
		STR	R0,ibicon__flags	;And store them back

		; --- Ensure win is initialised ---

		BL	win_init		;Initialise win

		; --- Initialise the workspace ---

		MOV	R0,#0			;No handlers yet
		STR	R0,ibicon__icons	;No siree

		; --- Set up the event handler ---

		MOV	R0,#-2			;Window is icon bar
		ADR	R1,ibicon__handler	;Routine to call
		MOV	R2,#0			;My handle
		MOV	R3,R9			;Pass workspace ^ to R12
		BL	win_eventHandler	;Add the handler
		MOV	R0,R1			;Point to the handler again
		BL	win_unknownHandler	;Ooo.. An unknown one too

		; --- Return to caller ---

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

		LTORG

ibicon__wSpace	DCD	0

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

		^	0,R9
ibicon__wStart	#	0

ibicon__flags	#	4			;Flags

ibicon__INITED	EQU	(1<<0)			;I've been initialised

ibicon__icons	#	4			;Event handler list

ibicon__wSize	EQU	{VAR}-ibicon__wStart

; --- list structure ---

		^	0
list__next	#	4			;The next block
list__iHandle	#	4			;The window handle
list__proc	#	4			;Handler code
list__iData	#	4			;Pointer to icon data
list__valid	#	4			;Pointer to validation
list__r10	#	4			;R10 to call with
list__r12	#	4			;R12 to call with

list__size	#	0

		AREA	|Sapphire$$LibData|,CODE,READONLY

		DCD	ibicon__wSize		;Workspace size
		DCD	ibicon__wSpace		;Workspace pointer
		DCD	0			;Scratchpad size
		DCD	ibicon_init		;Initialisation code

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

		END

