;*
;
; ### Gadgets 2 by JM v1.0 ###
;
; - Created 911014 by JM -
;
; Edited:
;
; - 911017 by JM -> v1.0	- lopullinen kommentoitu versio.
;
;

		include "exec/types.i"
		include "exec/nodes.i"
		include "exec/lists.i"
		include "exec/memory.i"
		include	"graphics/gfx.i"
		include	"graphics/gfxbase.i"
		include	"graphics/text.i"
		include	"intuition/intuition.i"
		include	"intuition/screens.i"

lib		macro			; käyttö: lib kirjasto,rutiini
		xref	_LVO\2		; määrittelee offsetin
		move.l	\1base(a4),a6	; ottaa kirjaston perusosoitteen
		jsr	_LVO\2(a6)	; kutsuu rutiinia _LVOxxx(a6)
		endm

flib		macro			; käyttö: flib kirjasto,rutiini
		xref	_LVO\2		; määrittelee offsetin
		jsr	_LVO\2(a6)	; kutsuu rutiinia _LVOxxx(a6)
		endm

exec		macro			; käyttö: exec rutiini
		xref	_LVO\1		; määrittelee offsetin
		move.l	$4,a6		; ottaa execin perusosoitteen
		jsr	_LVO\1(a6)	; kutsuu rutiinia _LVOxxx(a6)
		endm

fexec		macro			; käyttö: exec rutiini
		xref	_LVO\1		; määrittelee offsetin
		jsr	_LVO\1(a6)	; kutsuu rutiinia _LVOxxx(a6)
		endm

WFLAGS		set	SIMPLE_REFRESH!WINDOWDEPTH
WFLAGS		set	WFLAGS!WINDOWDRAG!WINDOWSIZING!WINDOWCLOSE

IDCMPFLAGS	set	CLOSEWINDOW!GADGETUP!MOUSEMOVE!REFRESHWINDOW

intuibase	equ	-4	; tila Intuition-kirjaston osoittimelle
gfxbase		equ	-8	; tila Graphics-kirjaston osoittimelle
window		equ	-12	; tila Window-osoittimelle
rp		equ	-16	; tila RastPort-osoittimelle
quit		equ	-20	; lippu: pitää poistua

;----------------------------------------------------------------------------
;
; Pääohjelma.  Alussa nollataan pinomuuttujat ja avataan tarvittavat
; kirjastot (Intuition ja Graphics).
;
main	link	a4,#-24			; varataan muuttujatilaa
	clr.l	intuibase(a4)		; nollataan muuttujat
	clr.l	gfxbase(a4)
	clr.l	window(a4)
	clr.w	quit(a4)		; nolla: ei poistuta

	lea	gfx(pc),a1		; grafiikkakirjaston nimi
	moveq	#0,d0			; kirjastoversio (mikä tahansa)
	exec	OpenLibrary		; kutsutaan OpenLibrary()ä
	move.l	d0,gfxbase(a4)		; talletetaan gfx:n perusosoite
	beq	cleanup			; jos kirjastoa ei ole, pois!

	lea	intui(pc),a1		; Intuition-kirjaston nimi
	moveq	#0,d0			; kirjastoversio (mikä tahansa)
	fexec	OpenLibrary		; kutsutaan OpenLibrary()ä
	move.l	d0,intuibase(a4)	; talletetaan I:n perusosoite
	beq	cleanup			; jos kirjastoa ei ole, pois!

	move.l	#$31303000,buffer	; asetetaan puskuriin "100",0

; Avataan ikkuna.  Intuition liittää gadgetit automaattisesti ikkunaan,
; koska niiden osoitin on asetettu NewWindow-struktuuriin.

	lea	Newwindow,a0		; NewWindow-struktuurin osoite
	lib	intui,OpenWindow	; kutsutaan OpenWindow()ia
	move.l	d0,window(a4)		; talletetaan Window:n osoite
	beq	cleanup			; jos ei auennut, pois!
	move.l	d0,a0
	move.l	wd_RPort(a0),rp(a4)	; otetaan RastPortin osoite
	move.l	wd_UserPort(a0),a5	; ikkunan viestiportti a5:een

;----------------------------------------------------------------------------
;
; Silmukka, jossa odotetaan IDCMP-viestejä ja käsitellään niiden komennot.
; Odottaminen tapahtuu Execin Wait-rutiinilla.
; Kun ohjelma saa CLOSEWINDOW-viestin, asetetaan lippu merkiksi siitä, että
; ohjelman pitäisi poistua.  Sitten luetaan muut mahdolliset IDCMP-viestit,
; minkä jälkeen ohjelma päättyy.
; Kun käyttäjä vapauttaa jomman kumman gadgetin, ohjelma päivittää näytöllä
; olevan arvon.  Liukusäätimen käytön aikana ohjelma saa MOUSEMOVE-viestejä,
; joista näyttö myös päivitetään.
; Ikkunan virkistyspyyntö (REFRESHWINDOW) aiheuttaa säätöarvon tulostuksen,
; gadgettien päivittämisestä huolehtii Intuition itse.
;
	bsr	showres			; tulostetaan alkup. arvo ikkunaan

loop	tst.w	quit(a4)		; pitääkö poistua?
	bne	cleanup			; joop -> voe tokkiisa

w_idcmp	moveq	#0,d0			; bittimaski = 0
	move.b	MP_SIGBIT(a5),d1	; signaalibitin numero
	bset	d1,d0			; muunnetaan bittimaskiksi
	exec	Wait			; odotetaan IDCMP-viestiä

nextmsg	move.l	a5,a0			; viestiportti
	exec	GetMsg			; otetaan saapunut viesti
	tst.l	d0
	beq.s	loop			; häh? ei viestiä? odotetaan lisää!
	move.l	d0,a1			; saadun viestin osoite a1:een
	move.l	im_Class(a1),d2		; viestin tyyppi d2:een
	move.w	im_Code(a1),d3		; koodi (esim. näppäimen numero)
	fexec	ReplyMsg		; vastataan viestiin

	cmp.l	#CLOSEWINDOW,d2		; painettiinko sulkunappulaa?
	bne.s	10$			; ei -> hyppää
	move.w	#1,quit(a4)		; kyllä: asetetaan lippu
	bra.s	nextmsg			; luetaan loput viestit

10$	cmp.l	#REFRESHWINDOW,d2	; ikkunan päivityspyyntö?
	bne.s	20$			; ei -> täytyy olla GADGET tai MOUSE
	move.l	window(a4),a0
	lib	intui,BeginRefresh	; aloitetaan päivittäminen
	bsr	showres			; päivitetään (showres ei sotke a6:a)
	move.l	window(a4),a0
	moveq	#-1,d0			; lippu: virkistys suoritettu
	flib	intui,EndRefresh	; aloitetaan päivittäminen
	bra.s	nextmsg

;----------------------------------------------------------------------------
; Jos tullaan tänne, viesti ei ollut CLOSEWINDOW eikä REFRESHWINDOW.  Siispä
; sen täytyy olla joko GADGETUP tai MOUSEMOVE, koska muita ei Intuitionilta
; ole pyydetty.  Molemmista viesteistä päivitetään ikkunassa näkyvä lukuarvo,
; koska MOUSEMOVE tarkoittaa liukusäätimen säätämistä ja GADGETUP sitä, että
; jompi kumpi gadgetti on vapautettu ja sen arvo saattaa siten olla muuttunut.
;
20$	bsr	showres			; päivitetään arvo
	bra.s	nextmsg

;----------------------------------------------------------------------------
;
; cleanup sulkee kaiken, mikä oli avoinna.
;
cleanup	move.l	window(a4),d0		; onko ikkuna auki?
	beq.s	101$			; ei -> hypätään
	move.l	d0,a0
	lib	intui,CloseWindow	; suljetaan ikkuna

101$	move.l	gfxbase(a4),d0		; graphics auki?
	beq.s	201$			; ei -> loikataan
	move.l	d0,a1
	exec	CloseLibrary		; suljetaan graphics-kirjasto

201$	move.l	intuibase(a4),d0	; intuition auki?
	beq.s	202$			; ei -> harpataan
	move.l	d0,a1
	exec	CloseLibrary		; suljetaan intuition

202$	unlk	a4			; vapautetaan pinoalue
	moveq	#0,d0			; ei virhettä
	rts				; poistutaan

;----------------------------------------------------------------------------
;
; Päivitysrutiini, joka tulostaa ikkunaan proportional gadgetin säätöä
; vastaavan luvun.  Luku saadaan kertomalla proportional gadgetin arvo
; long int gadgettiin asetetulla luvulla ja jakamalla tulos 65535:llä.
;
showres	lea	LongIntGadget,a0	; long int -gadgetti
	move.l	gg_SpecialInfo(a0),a2	; StringInfo-osoitin a1:een
	move.l	si_LongInt(a2),d1	; lukuarvo gadgetista
	bpl.s	1$			; positiivinen -> hyppää
	neg.l	d1			; muutetaan negatiivinen positiiviseksi
1$	lea	PropGadget,a0
	move.l	gg_SpecialInfo(a0),a1	; PropInfo-osoitin a1:een
	move.w	pi_VertPot(a1),d2	; säätimen asento

	move.l	d1,d0
	mulu.w	d2,d0			; kerrotaan alemmat 16 bittiä
	swap	d1
	mulu.w	d2,d1			; kerrotaan ylemmät 16 bittiä

	add.l	#32767,d0		; lisätään pyöristys (puolet jakajasta)
	swap	d1			; d1[31-16]=[31-16], d1[15-0]=[47-32]
	move.l	d1,d2
	clr.w	d2			; nollataan tuloksen bitit [47-32]
	add.l	d2,d0			; ynnätään eri kertolaskujen tulokset
	moveq	#0,d2
	addx.w	d2,d1			; lisätään ylimpään wordiin muistinumero

	move.l	#65535,d2		; jakaja
	bsr	divu48			; jaetaan tulo 65535:llä
	tst.l	si_LongInt(a2)		; oliko arvo alunperin negatiivinen?
	bpl.s	2$			; ei -> hyppää
	neg.l	d0			; oli -> muuta tulos negatiiviseksi
2$	lea	format(pc),a0		; muotoilumerkkijono (format string)
	bsr	display			; tulostetaan luku ikkunaan
	rts

;----------------------------------------------------------------------------
;
; Tämä rutiini jakaa d0:ssa ja d1:ssä olevan 48-bittisen luvun d2:ssa oleval-
; la 32-bittisellä luvulla.  Jaettavan alimmat 32 bittiä ovat d0:ssa ja ylim-
; mät 16 bittiä d1:n 16 alimmassa bitissä.  Rutiini ei aina toimi oikein, jos
; jakajan ylin bitti on ykkönen (jakajan on oltava 2147483647 tai alle).
;
divu48	movem.l	d2-d5,-(sp)	; rekisterit d2, d3, d4 ja d5 pinoon
	moveq.l	#0,d3		; nollataan apuakku
	moveq.l	#47,d5		; jaettavan bittien määrä -1
1$	roxl.l	#1,d0		; jaettavan alimmat 32 bittiä
	roxl.w	#1,d1		; jaettavan eniten merkitsevät 16 bittiä
	roxl.l	#1,d3		; väliaikainen akku
	cmp.l	d2,d3		; verrataan jakajaan
	bcs.s	2$		; ei voi vähentää -> hyppää
	sub.l	d2,d3		; vähennetään
	ori	#16,ccr		; asetetaan X-lippu (tulokseen ykkösbitti)
2$	roxl.l	#1,d4		; bitti lisää tulokseen
	dbf	d5,1$		; silmukka toistetaan 48 kertaa
	move.l	d4,d0		; osamäärä d0:aan
	move.l	d3,d1		; jakojäännös d1:een
	movem.l	(sp)+,d2-d5	; rekisterit pinosta
	rts

;----------------------------------------------------------------------------
;
; Tämä rutiini tulostaa datarekistereissä annetut parametrit a0:ssa annetun
; muotoilumerkkijonon ohjeiden mukaan Text-rutiinilla.  Tässä ohjelmassa
; tarvitaan tulostaa vain d0:n arvo.
; Koska Execin RawDoFmt ei palauta lopullisen merkkijonon pituutta, se jou-
; dutaan laskemaan käsin silmukassa.
;
display	movem.l	d0-d7/a0-a3/a6,-(sp)	; tulostett. param. ja a0-a3/a6 pinoon
	move.l	sp,a1			; pino-osoitin a1:een (parametriosoitin)
	lea	putchar(pc),a2		; rutiini, joka laittaa merkit puskuriin
	lea	output_buffer,a3	; tulostuspuskuri
	exec	RawDoFmt		; muotoillaan tulostus
	move.l	a3,a2			; puskurin osoite a2:een
1$	tst.b	(a2)+			; mitataan merkkijonon pituus
	bne.s	1$			; silmukka, kunnes loppunolla
	subq.w	#1,a2			; vähennetään loppunollan viemä tila
	sub.l	a3,a2			; vähennetään puskurin alkuosoite

	move.l	rp(a4),a1		; ikkunan RastPort
	moveq	#1,d0			; piirtokynän numero
	lib	gfx,SetAPen		; asetetaan tekstin väri
	move.l	rp(a4),a1		; ikkunan RastPort
	moveq	#9,d0			; piirtokynän x-paikka
	moveq	#45,d1			; piirtokynän y-paikka
	flib	gfx,Move		; siirretään piirtokynä
	move.l	a3,a0			; tekstin alkuosoite (puskuri)
	move.l	rp(a4),a1		; ikkunan RastPort
	move.l	a2,d0			; tulostettavan tekstin pituus
	flib	gfx,Text		; tulostetaan teksti
	movem.l	(sp)+,d0-d7/a0-a3/a6	; otetaan rekisterit pinosta
	rts
putchar	move.b	d0,(a3)+		; tämä rutiini laittaa merkit puskuriin
	rts

;----------------------------------------------------------------------------
;
gfx	dc.b	"graphics.library",0	; kirjastojen nimet
intui	dc.b	"intuition.library",0
format	dc.b	'Arvo=%10.10ld',0	; tulostuksen muotoilumerkkijono
	ds.w	0			; varmistetaan osoite parilliseksi

;----------------------------------------------------------------------------
;
; Muuttuvat struktuurit, jotka on sijoitettu erilliseen data-tyyppiseen
; lohkoon, jolloin itse ohjelman koodi pysyy muuttumattomana suositusten
; mukaisesti.

		section	struct,DATA
Newwindow	dc.w	10,100		; ikkunan koordinaatit (x,y)
		dc.w	250,60		; ikkunan koko (x,y)
		dc.b	0,1		; kynien värit
		dc.l	IDCMPFLAGS	; vahdi sulkunappulaa yms
		dc.l	WFLAGS		; liput
		dc.l	LongIntGadget	; ensimmäinen gadget
		dc.l	0		; ei omaa checkmarkkia
		dc.l	WTitle		; ikkunan otsikkopalkin teksti
		dc.l	0		; näytön osoitin, ei tarvita tässä
		dc.l	0		; ei BitMap-osoitinta
		dc.w	250,60		; ikkunan minimikoko
		dc.w	1000,1000	; ikkunan maksimikoko
		dc.w	WBENCHSCREEN	; näytön tyyppi = WORKBENCH

; gadgetit ja niihin liittyvät apustruktuurit
LongIntGadget	dc.l	PropGadget	; osoitin seuraavaan gadgettiin
		dc.w	50,20		; x- ja y-paikka
		dc.w	160,10		; x- ja y-koko
		dc.w	GADGHCOMP	; liput
		dc.w	RELVERIFY|LONGINT; viesti vasta vapautettaessa
		dc.w	STRGADGET	; tyyppi = string / long int
		dc.l	LongIntBorder	; kehys gadgetin ympärille ->
		dc.l	0		; aktivoidessa ei uutta kuviota
		dc.l	LongIntText	; gadgetin teksti
		dc.l	0		; mutual exclude, ei käytössä
		dc.l	LongIntSInfo	; special info -> StringInfo
		dc.w	0		; gadget ID (käyttäjän käytettävissä)
		dc.l	0		; userdata (käyttäjän käytettävissä)

LongIntSInfo	dc.l	buffer		; puskuri gadgetin tekstille
		dc.l	undo_buffer	; undo-puskuri
		dc.w	0		; paikka, jossa ollaan editoimassa
		dc.w	33		; merkkipuskurin koko - 1
		dc.w	0		; ensimmäinen näytöllä näkyvä merkki
		dc.w	0,0,0,0,0	; Intuitionin sisäisiä muuttujia
		dc.l	0		; ei käytössä 1.3:ssa
		dc.l	100		; longint-arvo, jota Intuition päivittää
		dc.l	0		; vaihtoehtoinen näppäinkartta

; struktuuri, joka määrittelee gadgetin ympärille piirrettävän kehyksen
LongIntBorder	dc.w	-2,-2		; suhteellinen paikka
		dc.b	1,2		; piirtovärit
		dc.b	RP_JAM1		; piirtomoodi
		dc.b	5		; koordinaattiparien määrä
		dc.l	LongIntVectors	; koordinaattiparitaulukko ->
		dc.l	0		; ei useampia Border-struktuureja

LongIntVectors	dc.w	0,0,163,0,163,11,0,11,0,0 ; viivojen koordinaattiparit

LongIntText	dc.b	1,2		; piirtovärit
		dc.b	RP_JAM1		; piirtomoodi
		dc.b	0		; (ei käytössä)
		dc.w	-40,0		; suhteellinen paikka
		dc.l	0		; fontti = oletusfontti
		dc.l	LongInt_Text	; teksti
		dc.l	0		; ei lisätekstiä

PropGadget	dc.l	0		; ei enempää gadgetteja
		dc.w	-33,11		; x- ja y-paikka
		dc.w	16,-14		; x- ja y-koko
		dc.w	GADGHCOMP!GRELRIGHT!GRELHEIGHT; liput
		dc.w	RELVERIFY!FOLLOWMOUSE; viesti vasta vapautettaessa
		dc.w	PROPGADGET	; tyyppi = proportional
		dc.l	KnobImage	; tilaa nappulan kuvalle (Image-strukt.)
		dc.l	0		; aktivoidessa ei uutta kuviota
		dc.l	0		; ei tekstiä
		dc.l	0		; mutual exclude, ei käytössä
		dc.l	PropPInfo	; special info -> PropInfo
		dc.w	0		; gadget ID (käyttäjän käytettävissä)
		dc.l	0		; userdata (käyttäjän käytettävissä)

PropPInfo	dc.w	AUTOKNOB!FREEVERT; liput: autom. nuppi, pystys. liike
		dc.w	0		; vaakasuunnan säätöarvo
		dc.w	0		; pystysuunnan säätöarvo
		dc.w	0		; vaakasuunnan 'nupin koko'
		dc.w	4095		; pystysuunnan 'nupin koko'
		dc.w	0,0,0,0,0,0	; Intuitionin sisäisiä muuttujia

; Image-struktuuri, johon Intuition määrittelee säätönappulan koon, paikan
; ja kuvion (automaattisesti, koska käytettiin AUTOKNOB-toimintaa):
KnobImage	dc.w	0,0,0,0,0	; paikka, koko, bittitasojen määrä
		dc.l	0		; osoitin itse kuvioon
		dc.b	0,0		; PlanePick, PlaneOnOff
		dc.l	0		; osoitin seuraavaan Image-struktuuriin

;----------------------------------------------------------------------------
;
; Tekstit:
;
WTitle		dc.b	'SimpleRefresh-ikkuna',0
LongInt_Text	dc.b	'Max:',0
		ds.w	0

;----------------------------------------------------------------------------
;
; Tarvittavat merkkijonopuskurit on sijoitettu omaan BSS-hunkkiinsa, jolloin
; ne eivät vie tilaa ohjelman käännetystä versiosta, mutta niille varataan
; automaattisesti tilaa ohjelmaa ladattaessa.
;
		section	puskurit,bss
buffer		ds.b	34		; LongInt-gadgetin tekstipuskuri
undo_buffer	ds.b	34		; vähintään yhtä iso kuin edellinen!!
output_buffer	ds.b	100		; tulostuspuskuri

		end

