;
; writable.s
;
; Writable dialogue boxes (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:dbox
		GET	sapphire:fastMove
		GET	sapphire:msgs
		GET	sapphire:sapphire
		GET	sapphire:string

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

		AREA	|Sapphire$$Code|,CODE,READONLY

; --- writable ---
;
; On entry:	R0 == pointer to writable dialogue block
;		R1 == pointer to default string to display, or 0 for null
;		R2 == pointer to routine to call when string set
;		R3 == value to pass to routine in R10
;		R4 == value to pass to routine in R12
;
; On exit:	R0 == dialogue handle of created dialogue box
;		May return an error
;
; Use:		Displays a writable dialogue box, i.e. one with a writable
;		icon and OK button, used instead of writable menu items,
;		for reasons to do with caret blinking and pointer changing.
;
;		The writable dialogue block consists of:
;
;		Size	Meaning
;		~~~~	~~~~~~~
;		4	Flags (see below)
;		n	Validation string to use, may be null
;		m	Title string (message tag) to display
;
;		The flags are:
;
;		Bit	Meaning
;		~~~	~~~~~~~
;		0-7	Maximum string length
;		8	Right align text in writable icon
;		9-31	Reserved; must be 0
;
;		The routine returns a dialogue handle because you may want
;		to attach a numWrite control to the writable icon, which
;		is icon number 0.
;
;		The handler routine is passed:
;
;		R0 == pointer to string typed in
;		R1 == dialogue box handle (for numWrite again)
;		R10, R12 as set up here
;
;		It must preserve all registers.  If the carry flag is set
;		on exit, the dialogue box will not be closed.  If it is
;		clear, the dialogue may be closed depending on the button
;		status.
;
;		Note that this routine does *not* require a template --
;		a suitable window is generated at run-time.

		EXPORT	writable
writable	ROUT

		STMFD	R13!,{R1-R3,R12,R14}	;Save some registers away
		WSPACE	wrt__wSpace		;Find my workspace pointer

		; --- Save the handler information ---

		ADR	R14,wrt__proc		;Point to the handler stuff
		STMIA	R14,{R2-R4}		;Save the handler info away
		MOV	R3,R0			;Keep the description block

		; --- Save the default string away ---

		ADR	R0,wrt__buffer		;Point to writable buffer
		CMP	R1,#0			;Is there a default string?
		STREQB	R1,[R0,#0]		;No -- save a null string
		BLNE	str_cpy			;Otherwise copy the string

		; --- Set up the dialogue box sizes ---

		LDR	R1,[R3,#0]		;Load the string length/flags
		AND	R0,R1,#&FF		;Just get the bottom byte
		ADD	R0,R0,#1		;Allow for the terminator
		STR	R0,wrt__dbDef+wOff__writeData+8
		CMP	R0,#41			;Is the string really big?
		MOVGT	R0,#41			;Yes -- make it sane at least
		MOV	R0,R0,LSL #4		;Multiply up to pixels
		ADD	R0,R0,#106		;Get the left of the icon
		RSB	R0,R0,#0		;And make it negative
		STR	R0,wrt__dbDef+wOff__writeBox
		SUB	R0,R0,#24		;Get left side of the window
		STR	R0,wrt__dbDef+wOff__open
		STR	R0,wrt__dbDef+wOff__extent

		; --- Fix up string alignment ---

		LDR	R14,wrt__dbDef+wOff__writeFlag
		TST	R1,#wrtFlag_rAlign	;Do we right align text?
		ORRNE	R14,R14,#&200		;Yes -- set the bit then
		BICEQ	R14,R14,#&200		;No -- clear it instead
		STR	R14,wrt__dbDef+wOff__writeFlag

		; --- Fill in the validation string ---

		ADR	R0,wrt__valid		;Point to validation buffer
		ADR	R1,wrt__x7		;Point to base validation
		BL	str_cpy			;Copy it onto the end
		ADD	R1,R3,#4		;Point to validation string
		LDRB	R14,[R1],#1		;Load the first byte
		CMP	R14,#32			;Is this an empty string?
		BLO	%20writable		;Yes -- miss this bit out

		MOV	R2,#';'			;Put a delimiter string in
		STRB	R2,[R0],#1		;Save in validation buffer
10writable	STRB	R14,[R0],#1		;Save the valid character
		LDRB	R14,[R1],#1		;Load another byte
		CMP	R14,#32			;Is this the string end?
		BHS	%10writable		;No -- go round again
		MOV	R14,#0			;Null terminate nicely
		STRB	R14,[R0],#1		;Save it in the buffer

		; --- Finally, fill in the title string ---

20writable	MOV	R0,R1			;Point to title message tag
		BL	msgs_lookup		;Find the message string
		MOV	R1,R0			;Point to the message
		ADR	R0,wrt__title		;Point to the title buffer
		BL	str_cpy			;And copy that over nicely

		; --- Build the dialogue box ---

		ADR	R0,wrt__dbDef		;Point to the dialogue defn
		BL	dbox_fromDefn		;Create a dialogue box
		BVS	%90writable		;Return if it failed

		ADR	R1,wrt__handler		;Point to the handler
		MOV	R2,R0			;Pass dialogue handle in R10
		MOV	R3,R12			;Pass workspace in R12
		BL	dbox_eventHandler	;Set up the event handler

		MOV	R1,#dbOpen_pointer+dbOpen_trans
		BL	dbox_open		;Display the dialogue box
		LDMFD	R13!,{R1-R3,R12,R14}	;Restore all the registers
		BICS	PC,R14,#V_flag		;Return without an error

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

90writable	LDMFD	R13!,{R1-R3,R12,R14}	;Restore all the registers
		ORRS	PC,R14,#V_flag		;Return the error pointer

wrt__x7		DCB	"x7",0			;Tim's neat writable border

		LTORG

; --- wrt__handler ---
;
; On entry:	R0 == dialogue box event code
;		R1-R7 == depend on the event type
;		R10 == dialogue box handle
;		R12 == pointer to my workspace
;
; On exit:	--
;
; Use:		Handles events for the writable dialogue box.

wrt__handler	ROUT

		CMP	R0,#dbEvent_close	;Someone closed my dialogue?
		BEQ	%10wrt__handler		;Yes -- destroy it then
		CMP	R0,#dbEvent_OK		;Is it an OK click?
		CMPNE	R0,#wrtIcon__ok		;Or a click on the OK button?
		MOVNES	PC,R14			;No -- then return to caller

		; --- Handle an OK click ---

		STMFD	R13!,{R0-R3,R10,R12,R14} ;Save loads of registers
		MOV	R2,R1			;Look after the button state
		MOV	R0,R10			;Get the dialogue handle
		MOV	R1,#wrtIcon__ok		;And the OK button handle
		BL	dbox_slab		;Slab the button in

		; --- Call the user's handler ---

		ADR	R0,wrt__buffer		;Point to the string
		MOV	R1,R10			;Get the dialogue box handle
		ADR	R14,wrt__proc		;Find his event handler
		LDMIA	R14,{R3,R10,R12}	;Load all the handler stuff
		ADDS	R0,R0,#0		;Clear C flag cunningly
		MOV	R14,PC			;Set up return address
		MOV	PC,R3			;And call the handler

		; --- Find out what to do next ---

		TSTCS	R2,#0			;Set Z flag if carry set
		TSTCC	R2,#1			;Otherwise, test Adjustness
		MOV	R0,R1			;Get the dialogue handle
		BLEQ	dbox_close		;If Select then close dbox
		BL	dbox_unslab		;Unslab the OK button
		BLEQ	dbox_destroy		;If Select then trash dbox
		LDMFD	R13!,{R0-R3,R10,R12,PC}^ ;And return to caller

		; --- The dialogue box closed ---

10wrt__handler	STMFD	R13!,{R0,R14}		;Save some registers
		MOV	R0,R10			;Get the dialogue handle
		BL	dbox_destroy		;Kill the dialogue box
		LDMFD	R13!,{R0,PC}^		;Return to caller

		LTORG

; --- wrt_init ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Initialises the writable dialogue box for use.

		EXPORT	wrt_init
wrt_init	ROUT

		STMFD	R13!,{R12,R14}		;Save some registers
		WSPACE	wrt__wSpace		;Load my workspace pointer
		LDR	R14,wrt__flags		;Load the flags word nicely
		TST	R14,#wFlag__inited	;Have we done this already?
		LDMNEFD	R13!,{R12,PC}^		;Yes -- return to caller

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

		STMFD	R13!,{R0-R2}		;Save some more registers
		ORR	R14,R14,#wFlag__inited	;Set the initialised flag
		STR	R14,wrt__flags		;Save the flags back again
		BL	dbox_init		;Make sure dboxes are going

		; --- Now copy the window definition over ---

		ADR	R0,wrt__dbDef		;Point to the workspace block
		ADR	R1,wrt__window		;Point to the window def
		MOV	R2,#wrt__windSize	;Get the size of the block
		BL	fastMove		;Copy the block over nicely

		; --- Fill in bits of the window definition ---

		ADR	R14,wrt__title		;Point to the title buffer
		STR	R14,[R0,#wOff__titleData]
		ADR	R14,wrt__buffer
		STR	R14,[R0,#wOff__writeData]
		ADR	R14,wrt__valid
		STR	R14,[R0,#wOff__writeData+4]

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

		LTORG

wrt__wSpace	DCD	0

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

		; --- Icon numbers ---

wrtIcon__write	EQU	0			;The writable icon
wrtIcon__ok	EQU	1			;The OK button

		; --- Flags ---

wrtFlag_rAlign	EQU	(1<<8)			;Align text to right side

;----- Window definition ----------------------------------------------------

; --- Note ---
;
; The main window definition here gets copied into workspace so that I can
; modify it nicely at runtime, to change the width of the window etc.

; --- Macro: WOFF ---
;
; Arguments:	label == symbol to assign with current offset into window def
;
; Use:		Sets a symbol to an offset in the window definition

		MACRO
$label		WOFF
$label		EQU	{PC}-wrt__window
		MEND

		; --- The main window block ---

wrt__window

wOff__open	WOFF
		DCD	-324,-96,0,0		;Width dynamically adjusted
		DCD	0,0			;Window doesn't scroll (hope)
		DCD	-1			;Always open on the top
		DCD	&84170002		;Window flags word (various)
		DCB	7,2,7,1,3,1,2,0		;Window colours words

wOff__extent	WOFF
		DCD	-324,-96,0,0		;Dynamically adjust width
		DCD	&00000109		;Window title bar flags
		DCD	&00000000		;Work area button type
		DCD	1			;Wimp sprite area, I think
		DCD	0			;Default minimum sizes

wOff__titleData	WOFF
		DCD	0,-1,24			;Title bar icon data
		DCD	2			;2 icons following

		; --- The writable area icon ---

wOff__writeBox	WOFF
		DCD	-300,-68,-110,-28	;24 in from the left

wOff__writeFlag	WOFF
		DCD	&0700F131		;Icon flags word

wOff__writeData	WOFF
		DCD	0,0,0			;Fill in all the data later

		; --- The OK button ---

		DCD	-72,-72,-24,-24		;Icon bounding box
		DCD	&17003139		;Icon flags word
		DCD	wrt__ok,wrt__x2,3	;Icon data strings

wrt__windSize	WOFF

		; --- Indirected text for OK button ---

wrt__ok		DCB	"OK",0			;Button text string
wrt__x2		DCB	"x2",0			;Button border command

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

		^	0,R12
wrt__wStart	#	0

wrt__flags	#	4			;Various flags

		; --- The user's handler routine ---

wrt__proc	#	4			;The routine to call
wrt__R10	#	4			;Value to pass in R10
wrt__R12	#	4			;Value to pass in R12

		; --- The copy of the window definition ---

wrt__dbDef	#	wrt__windSize		;The window definition copy
wrt__valid	#	24			;Icon validation string
wrt__title	#	24			;Window title text string
wrt__buffer	#	256			;The actual data string

wrt__wSize	EQU	{VAR}-wrt__wStart

wFlag__inited	EQU	(1<<0)			;Have we initialised yet?

		AREA	|Sapphire$$LibData|,CODE,READONLY

		DCD	wrt__wSize
		DCD	wrt__wSpace
		DCD	0
		DCD	wrt_init

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

		END
