;*
;
; ### Screens and Windows by JM v1.0 ###
;
; - Created 910705 by JM -
;
; Edited:
;
; - 910715 by JM -> v1.0	- lopullinen kommentoitu versio.
;
;

; Include-tiedostot, joissa on määritelty käyttöjärjestelmään liittyviä
; struktuureja ja vakioita.

		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"


; Makrot, joiden avulla käyttöjärjestelmän rutiineja on helpompi kutsua.
; Makrot määrittelevät automaattisesti kaikki kutsutut rutiinit linkkeriä
; varten ja lataavat kirjaston perusosoitteen a6:een ennen rutiinin kut-
; sumista.
; Esimerkiksi "lib intui,OpenWindow" purkautuu käskyiksi
;   xref   _LVOOpenWindow
;   move.l intuibase(a4),a6
;   jsr    _LVOOpenWindow(a6)
;
; flib vastaa lib-makroa, mutta ei lataa automaattisesti kirjaston perus-
; osoitetta a6:een.  Tästä on hyötyä kutsuttaessa useita samassa kirjas-
; tossa olevia rutiineja peräkkäin (a6:n arvo säilyy kutsujen aikana).

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		; maarittelee offsetin
		move.l	$4,a6		; ottaa execin perusosoitteen
		jsr	_LVO\1(a6)	; kutsuu rutiinia _LVOxxx(a6)
		endm


; Määritellään offsetit pinossa oleviin muuttujiin.  Muuttujatila varataan
; ohjelman alussa link-käskyllä.

intuibase	equ	-4	; tila Intuition-kirjaston osoittimelle
gfxbase		equ	-8	; tila Graphics-kirjaston osoittimelle
window1		equ	-12	; tila Window-osoittimelle
window2		equ	-16	; tila Window-osoittimelle
screen		equ	-20	; tila Screen-osoittimelle
rp1		equ	-24	; tila RastPort-osoittimelle
rp2		equ	-28	; tila RastPort-osoittimelle
quit		equ	-30	; lippu: pitää poistua

; muuttujat viivojen piirtoa varten:

x1		equ	-32	; alkupisteen koordinaatit
y1		equ	-34
x2		equ	-36	; loppupisteen koordinaatit
y2		equ	-38
dx1		equ	-40	; alkupisteen x-suunta
dy1		equ	-42	; alkupisteen y-suunta
dx2		equ	-44	; loppupisteen x-suunta
dy2		equ	-46	; loppupisteen y-suunta

pen		equ	-48	; väri
linenum		equ	-50	; laskuri
moodi		equ	-52	; odotusmoodi

STARTX		equ	200	; aloitus-X
STARTY		equ	80	; aloitus-Y
;MINX		equ	6	; pienin sallittu x-arvo
;MINY		equ	14	; pienin sallittu y-arvo
;MAXX		equ	-20	; maksimiraja (ikkunan koko+MAXX)
;MAXY		equ	-4	; maksimiraja (ikkunan koko+MAXY)


; Pääohjelma.  Alussa nollataan pinomuuttujat ja avataan tarvittavat
; kirjastot (Intuition ja Graphics).

main	link	a4,#-52			; varataan muuttujatilaa
	clr.l	intuibase(a4)		; nollataan muuttujat
	clr.l	gfxbase(a4)
	clr.l	window1(a4)
	clr.l	window2(a4)
	clr.l	screen(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)
	exec	OpenLibrary		; kutsutaan OpenLibrary()ä
	move.l	d0,intuibase(a4)	; talletetaan I:n perusosoite
	beq	cleanup			; jos kirjastoa ei ole, pois!

; Avataan näyttö sekä ikkunat ja otetaan ikkunoiden RastPort-struktuurien
; osoitteet viivojen piirtämistä varten.  Näytön ViewPort-struktuuriin
; asetetaan näytön värit LoadRGB4-rutiinilla.

	lea	Newscreen,a0		; NewScreen-struktuurin osoite
	lib	intui,OpenScreen	; avataan näyttö
	move.l	d0,screen(a4)		; osoitin talteen
	beq	cleanup			; pois, jos ei auennut
	move.l	d0,a0			; näytön osoitin
	lea	sc_ViewPort(a0),a0	; näytön ViewPort
	lea	colors(pc),a1		; väritaulukko
	moveq	#8,d0			; värien määrä
	lib	gfx,LoadRGB4		; asetetaan värit

	lea	Newwindow1,a0		; NewWindow-struktuurin osoite
	move.l	screen(a4),nw_Screen(a0)
	lib	intui,OpenWindow	; kutsutaan OpenWindow()ia
	move.l	d0,window1(a4)		; talletetaan Window:n osoite
	beq	cleanup			; jos ei auennut, pois!
	move.l	d0,a0
	move.l	wd_RPort(a0),rp1(a4)	; otetaan RastPortin osoite

	lea	Newwindow2,a0		; NewWindow-struktuurin osoite
	move.l	screen(a4),nw_Screen(a0)
	lib	intui,OpenWindow	; kutsutaan OpenWindow()ia
	move.l	d0,window2(a4)		; talletetaan Window:n osoite
	beq	cleanup			; jos ei auennut, pois!
	move.l	d0,a0
	move.l	wd_RPort(a0),rp2(a4)	; otetaan RastPortin osoite

; Toinen ikkuna avattiin ilman IDCMP-lippuja.  Siksi Intuition ei avannut
; sille omaa IDCMP-viestiporttia.  Kopioidaan ensimmäisen ikkunan viesti-
; portin osoitin toiseen ikkunaan ja asetetaan IDCMP-liput ModifyIDCMP-
; rutiinilla.  Näin molemmat ikkunat saadaan käyttämään samaa viestiporttia.

	move.l	window2(a4),a0
	move.l	window1(a4),a1
	move.l	wd_UserPort(a1),wd_UserPort(a0)
	move.l	#IDCMPFLAGS2,d0
	lib	intui,ModifyIDCMP

; Asetetaan päätepisteiden koordinaatit ja suunnat viivojen piirtoa varten.
; Ohjelma piirtää aina kahdeksan viivaa ja vaihtaa sitten piirtoväriä.

	move.w	#STARTX,x1(a4)
	move.w	#STARTY,y1(a4)
	move.w	#1,dx1(a4)		; suunta alas oikealle
	move.w	#1,dy1(a4)
	move.w	#STARTX,x2(a4)
	move.w	#STARTY,y2(a4)
	move.w	#-1,dx2(a4)		; suunta ylös vasemmalle
	move.w	#-1,dy2(a4)

	move.w	#0,pen(a4)		; väri = 0
	clr.w	linenum(a4)		; viivan numero = 0
	clr.w	moodi(a4)		; moodi = 0

;----------------------------------------------------------------------------
;
; Silmukka, jossa odotetaan IDCMP-viestejä ja käsitellään niiden
; komennot.  Odottaminen tapahtuu Execin Wait-rutiinilla, mikäli jompi
; kumpi ikkunoista on aktiivinen.  Tällöin Intuition lähettää 10 kertaa
; sekunnissa IntuiTick-viestin, joka aiheuttaa uuden viivan piirron
; aktiivisena olevaan ikkunaan.  Jos molemmat ikkunat ovat passiivisia
; (naksauta hiirellä ikkunoiden ulkopuolella tai jonkin muun ohjelman
; ikkunassa), odottamiseen käytetään WaitTOF-rutiinia, joka palaa takaisin
; 50 kertaa sekunnissa.  Tällöin piirretään ikkunaan 1 50 viivaa sekunnissa.

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

	move.l	window1(a4),a0		; ikkunan Window-struktuuri
	move.l	wd_UserPort(a0),a5	; ikkunan viestiportti a5:een

	tst.w	moodi(a4)		; jompi kumpi ikkuna aktiivinen?
	beq	w_idcmp			; on: odota IDCMP-viestiä

	lib	gfx,WaitTOF		; muuten odotetaan 20 millisekuntia
	move.l	window1(a4),a2		; ikkunan 1 osoitin
	bsr	dlines			; piiretään viivoja ikkunaan 1
	bra	nextmsg			; tarkista, onko tullut viestejä

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	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)
	move.l	im_IDCMPWindow(a1),a2	; ikkunan osoitin a2:een

	exec	ReplyMsg		; vastataan viestiin

	cmp.l	#INTUITICKS,d2		; intuiticks-viesti?
	bne	nottick
	bsr	dlines			; piirretään viivoja ikkunoihin
	bra	nextmsg

nottick	cmp.l	#ACTIVEWINDOW,d2	; aktivoitiinko jompi kumpi ikkuna?
	bne	notact			; ei -->
	clr.w	moodi(a4)		; joo: asetetaan moodi nollaksi
	bra	nextmsg			; otetaan seuraava viesti

notact	cmp.l	#INACTIVEWINDOW,d2	; passivoituiko jompi kumpi ikkuna?
	bne	notiact			; ei --->
	move.w	#1,moodi(a4)		; joo: asetetaan moodi ykköseksi
	bra	nextmsg			; otetaan seuraava viesti

notiact	cmp.l	#RAWKEY,d2		; tyyppi = näppäinpainallus?
	bne	notkey			; ei --->
	cmp.b	#$4c,d3			; kursori ylös?
	bne	not_up			; ei --->
	move.l	a2,a0			; ikkunan osoitin
	move.w	wd_TopEdge(a0),d0	; y-paikka
	beq	nextmsg			; jos nolla, ei voida siirtää ylös -->
	moveq	#0,d0			; x-suunnan siirros = 0
	moveq	#-1,d1			; y-suunnan siirros = -1 (ylöspäin)
	lib	intui,MoveWindow	; siirretään ikkunaa
	bra	nextmsg			; katsotaan, onko muita viestejä

not_up	cmp.b	#$4d,d3			; kursori alas?
	bne	not_dow			; ei --->
	move.l	screen(a4),a0		; näytön osoitin
	move.w	sc_TopEdge(a0),d0	; y-paikka d0:aan
	cmp.w	#255,d0			; y-paikka > 255?
	bhi	nextmsg			; jos on, otetaan seuraava viesti
	moveq	#0,d0			; x-suunnan siirros = 0
	moveq	#1,d1			; y-suunnan siirros = 1 (alaspäin)
	lib	intui,MoveScreen	; siirretään näyttöä alas
	bra	nextmsg			; otetaan seuraava viesti

not_dow	cmp.b	#$4f,d3			; kursori vasemmalle?
	bne	nextmsg			; ei -->
	move.l	a2,a0			; ikkunan osoitin a0:aan
	move.w	wd_Width(a0),d0		; ikkunan leveys d0:aan
	cmp.w	wd_MinWidth(a0),d0	; leveys <= minimileveys?
	bls	nextmsg			; joo, seuraava viesti
	moveq	#-1,d0			; x-koon muutos = -1 (pienennä)
	moveq	#0,d1			; y-koon muutos = 0 (ei tee mitään)
	lib	intui,SizeWindow	; säädetään ikkunan kokoa
	bra	nextmsg			; otetaan seuraava viesti

notkey	cmp.l	#CLOSEWINDOW,d2		; tyyppi = ikkunan sulkunappula?
	bne	nextmsg			; ei, katsotaan onko muita viestejä
	move.w	#1,quit(a4)		; asetetaan lippu: pois!
	bra	nextmsg			; tarkistetaan, onko muita viestejä


; cleanup sulkee kaiken, mikä oli avoinna.  Ennen sulkemista testataan,
; että suljettava olio oli avautunut - esimerkiksi ikkunaa ei voi sulkea,
; ellei se ole auki (guru).  Jos olion osoitin on nolla, se merkitsee,
; ettei kyseinen olio ole auki.

cleanup	move.l	window2(a4),d0		; onko ikkuna auki?
	beq.s	100$			; ei -> hypätään
	move.l	d0,a0
	clr.l	wd_UserPort(a0)
	lib	intui,CloseWindow	; suljetaan ikkuna

100$	move.l	window1(a4),d0		; onko ikkuna auki?
	beq.s	101$			; ei -> hypätään
	move.l	d0,a0
	lib	intui,CloseWindow	; suljetaan ikkuna

101$	move.l	screen(a4),d0		; onko näyttö auki?
	beq.s	200$			; ei -> hypätään
	move.l	d0,a0
	lib	intui,CloseScreen	; suljetaan näyttö

200$	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
	rts				; poistutaan


;----------------------------------------------------------------------------
; Viivoja piirtelevä aliohjelma..  a2:ssa annetaan ikkunan osoitin.

dlines	move.l	wd_RPort(a2),a3		; RastPort
	subq.w	#1,linenum(a4)		; joko vaihdetaan väriä?
	bpl	1$			; ei -> hyppy
	move.w	#7,linenum(a4)		; asetetaan laskuriin taas 7
	move.w	pen(a4),d0		; nykyinen väri
	addq.w	#1,d0			; kasvatetaan ykkösellä
	and.w	#7,d0			; käytössä 8 väriä
	bne.s	10$
	moveq	#1,d0			; hypätään värin 0 (tausta) yli
10$	move.w	d0,pen(a4)		; tallennetaan uusi väri
	move.l	a3,a1			; RastPort
	lib	gfx,SetAPen		; asetetaan piirtoväri RastPorttiin

1$	move.w	dx1(a4),d1		; kasvatetaan x1:tä
	move.w	x1(a4),d0		; suunta
	bsr	lim_x
	move.w	d0,x1(a4)		; uusi arvo talteen
	move.w	d1,dx1(a4)		; suunta talteen

	move.w	dy1(a4),d1		; kasvatetaan y1:tä
	move.w	y1(a4),d0		; suunta
	bsr	lim_y
	move.w	d0,y1(a4)		; uusi arvo talteen
	move.w	d1,dy1(a4)		; suunta talteen

	move.w	dx2(a4),d1		; kasvatetaan x2:ta
	move.w	x2(a4),d0		; suunta
	bsr	lim_x
	move.w	d0,x2(a4)		; uusi arvo talteen
	move.w	d1,dx2(a4)		; suunta talteen

	move.w	dy2(a4),d1		; kasvatetaan y2:ta
	move.w	y2(a4),d0		; suunta
	bsr	lim_y
	move.w	d0,y2(a4)		; uusi arvo talteen
	move.w	d1,dy2(a4)		; suunta talteen

	move.w	x1(a4),d0		; alku-X
	move.w	y1(a4),d1		; alku-Y
	move.l	a3,a1			; RastPort
	lib	gfx,Move		; siirretään kynää ikkunassa

	move.w	x2(a4),d0		; loppu-X
	move.w	y2(a4),d1		; loppu-Y
	move.l	a3,a1			; RastPort
	flib	gfx,Draw		; piirretään viiva ikkunaan

	rts


lim_x	moveq	#0,d2
	move.b	wd_BorderLeft(a2),d2	; minimiarvo
	add.w	d1,d0			; kasvatetaan paikkaa
	cmp.w	d2,d0			; tuliko liian pieni?
	bhi.s	1$			; ei -> hyppy
2$	neg.w	d1			; vaihdetaan suunta
	move.w	d2,d0			; asetetaan lailliselle alueelle
	rts
1$	moveq	#0,d2
	move.b	wd_BorderRight(a2),d2	; lasketaan maksimiarvo
	not.w	d2
	add.w	wd_Width(a2),d2
	cmp.w	d2,d0			; tuliko liian suuri?
	bcc.s	2$			; joo, hyppy
	rts

lim_y	moveq	#0,d2
	move.b	wd_BorderTop(a2),d2	; minimiarvo
	add.w	d1,d0			; kasvatetaan paikkaa
	cmp.w	d2,d0			; tuliko liian pieni?
	bhi.s	1$			; ei -> hyppy
2$	neg.w	d1			; vaihdetaan suunta
	move.w	d2,d0			; asetetaan lailliselle alueelle
	rts
1$	moveq	#0,d2
	move.b	wd_BorderBottom(a2),d2	; lasketaan maksimiarvo
	not.w	d2
	add.w	wd_Height(a2),d2
	cmp.w	d2,d0			; tuliko liian suuri?
	bcc.s	2$			; joo, hyppy
	rts


gfx	dc.b	"graphics.library",0	; kirjastojen nimet
intui	dc.b	"intuition.library",0
	ds.w	0

;----------------------------------------------------------------------------
;
; Väritaulukko.  Värit ilmaistaan 16-bittisillä luvuilla, joiden 4 ylintä
; bittiä eivät merkitse mitään.  Loput 4 bitin ryhmät tarkoittavat kukin
; yhtä värikomponenttia (punainen, vihreä, sininen) eli luvut ovat muotoa
; 0RGB.

colors	dc.w	$272,$4b4,$9b2,$cc2,$f92,$f32,$c4a,$08a

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

		section	struct,DATA

; Ikkunan liput, jotka määräävät ikkunan ominaisuudet.  Erikoinen
; määrittelytapa johtuu siitä, että liput eivät mahdu yhdelle riville.

WFLAGS1		set	SIMPLE_REFRESH!NOCAREREFRESH!WINDOWDEPTH
WFLAGS1		set	WFLAGS1!WINDOWDRAG!WINDOWSIZING

WFLAGS2		set	SMART_REFRESH!NOCAREREFRESH!ACTIVATE!WINDOWDEPTH
WFLAGS2		set	WFLAGS2!WINDOWCLOSE!WINDOWDRAG!WINDOWSIZING

; IDCMP-liput, jotka kertovat, mistä tapahtumista Intuitionin on
; lähetettävä ohjelmalle viestejä.  Tässä ohjelmassa odotetaan
; mm. näppäimistöön ja ikkunan sulkemiseen liittyviä viestejä.

IDCMPWIN	set	ACTIVEWINDOW!INACTIVEWINDOW
IDCMPFLAGS1	set	RAWKEY!INTUITICKS!IDCMPWIN		; IDCMP
IDCMPFLAGS2	set	RAWKEY!INTUITICKS!CLOSEWINDOW!IDCMPWIN	; IDCMP

; Ikkunoiden avaamisessa tarvittava NewWindow-struktuuri, joka sisältää
; tiedot ikkunan koosta, paikasta, väreistä ja niin edelleen.  Koska
; ikkuna avataan omaan näyttöön on  näytön (Screen) osoitin asetettava
; ennen OpenWindow-kutsua (ks. ohjelmalistaus).

Newwindow1	dc.w	10,100		; ikkunan koordinaatit (x,y)
		dc.w	300,120		; ikkunan koko (x,y)
		dc.b	0,1		; kynien värit
		dc.l	IDCMPFLAGS1	; vahdi sulkunappulaa yms
		dc.l	WFLAGS1		; liput
		dc.l	0		; ei gadgetteja
		dc.l	0		; ei omaa checkmarkkia
		dc.l	WTitle1		; ikkunan otsikkopalkin teksti
		dc.l	0		; näytön osoitin, ei tarvita tässä
		dc.l	0		; ei BitMap-osoitinta
		dc.w	100,100		; ikkunan minimikoko
		dc.w	500,200		; ikkunan maksimikoko
		dc.w	CUSTOMSCREEN	; näytön tyyppi

Newwindow2	dc.w	320,20		; ikkunan koordinaatit (x,y)
		dc.w	300,200		; ikkunan koko (x,y)
		dc.b	0,1		; kynien värit
		dc.l	0		; IDCMP asetetaan myöhemmin
		dc.l	WFLAGS2		; liput
		dc.l	0		; ei gadgetteja
		dc.l	0		; ei omaa checkmarkkia
		dc.l	WTitle2		; ikkunan otsikkopalkin teksti
		dc.l	0		; näytön osoitin, ei tarvita tässä
		dc.l	0		; ei BitMap-osoitinta
		dc.w	100,100		; ikkunan minimikoko
		dc.w	640,256		; ikkunan maksimikoko
		dc.w	CUSTOMSCREEN	; näytön tyyppi


; Näyttöjä avattaessa käytetään NewScreen-struktuuria, joka sisältää
; tiedot näytön koosta, näyttömoodista, värien (itse asiassa bittitasojen)
; lukumäärästä ja muista tarvittavista parametreista.

Newscreen	dc.w	0,0		; näytön paikka (x,y)
		dc.w	640,256		; näytön koko (x,y)
		dc.w	3		; bittitasojen määrä (8 väriä)
		dc.b	0,1		; piirtovärit
		dc.w	V_HIRES		; haluttu näyttötila
		dc.w	CUSTOMSCREEN	; tyyppi
		dc.l	Textattr	; fontti
		dc.l	STitle		; näytön otsikkopalkin teksti
		dc.l	0		; gadgetit (tähän aina nolla!)
		dc.l	0		; CustomBitMap (normaalisti nolla)

;----------------------------------------------------------------------------
;
; Tarvittavan fontin ominaisuudet.  Fontin avaaminen ei ole välttämätöntä.
; Jos fonttia ei erikseen aseteta, Intuition käyttää systeemin oletus-
; fonttia.  WB 2.0:ssa se voi kuitenkin olla hyvinkin suuri, mikä saattaisi
; sotkea ohjelman toimintaa.  Siksi ohjelma käyttää eksplisiittisesti 9
; pisteen suhteuttamatonta Topaz-fonttia.

Textattr	dc.l	FontName	; fontin nimi
		dc.w	9		; korkeus
		dc.b	0,0		; tyyli ja liput


;----------------------------------------------------------------------------
;
; Tekstit:

STitle		dc.b	"Näyttö",0
WTitle1		dc.b	"SimpleRefresh-ikkuna",0
WTitle2		dc.b	"SmartRefresh-ikkuna",0
FontName	dc.b	"topaz.font",0

		ds.w	0

		end

