/**************************************************************************

                         Denne filen er en del av
                           EXEC's store C-kurs

                              Programmert av 
                    Ørjan Eriksen og Torstein Pettersen

                          visliste.c   leksjon 3 
  
**************************************************************************/

#include <exec/types.h>
#include <exec/memory.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>

#include <string.h>
#include "base.h"

/* variabler fra database.c */

extern struct Window *w,*lw;

/* funksjoner tilgjengelig utenfor denne modulen */

struct Liste *vislpost(struct Liste *,short);
void show_liste(struct Liste *);
void sjekkposisjon(struct Liste *);
void visliste(struct Liste *,struct Gadget *,char *);
void finnantall(struct Liste *);
void scroll_up_down(short);

/* lokal funksjon */
static void adjustprop(int);

/* lokale variabler */
static struct Liste *topp; /* peker til posten som er på toppen av vislistevinduet */
static int offset;		  /* posisjon til post på toppen av vislistevinduet */
static int antall;		  /* antall poster i listen */

/* Image data til pil opp og pil ned gadgetene */

static USHORT chip DownArrowData[] = {
	0x0000,0x0000,0x3FFF,0x0000,0x3E1F,0x0000,0x3E1F,0x0000,
	0x3E1F,0x0000,0x3003,0x0000,0x3807,0x0000,0x3C0F,0x0000,
	0x3E1F,0x0000,0x3F3F,0x0000,0x3FFF,0x0000,0x0000,0x0000
};
static USHORT chip UpArrowData[] = {
	0x0000,0x0000,0x3FFF,0x0000,0x3F3F,0x0000,0x3E1F,0x0000,
	0x3C0F,0x0000,0x3807,0x0000,0x3003,0x0000,0x3E1F,0x0000,
	0x3E1F,0x0000,0x3E1F,0x0000,0x3FFF,0x0000,0x0000,0x0000
};

/* posisjoner til ramme i vislistevinduet */

static SHORT vlistvectors[] = {
	0,0,396,0,396,114,0,114,0,0,1,0,1,114,
	290,114,290,0,291,0,291,114,395,114,395,0,
	395,10,0,10
	
};
static struct Border vlistborder = {5,12,2,0,JAM1,15,vlistvectors,NULL};

/* proposjonal gadget for skrolling av listen i vislistevinduet */

static struct PropInfo ScrollGadInfo = {
	AUTOKNOB|FREEVERT,-1,0,-1,65535,0,0,0,0,0
};
static struct Image ScrollImage = {0,0,14,10,0,NULL,0x0000,0x0000,NULL};
struct Gadget ScrollGad = {
	NULL,404,37,22,91,
	GADGHBOX,FOLLOWMOUSE|RELVERIFY|GADGIMMEDIATE,PROPGADGET,
	(APTR)&ScrollImage,NULL,NULL,NULL,(APTR)&ScrollGadInfo,20,NULL
};

/* pil opp og ned for skrolling av listen i vislistevinduet */

static struct Image DownArrowImage = {
	0,0,18,12,2,DownArrowData,0x0001,0x0000,NULL
};

static struct Gadget DownArrowGad = {
	&ScrollGad,406,25,18,12,
	GADGIMAGE,RELVERIFY|GADGIMMEDIATE,BOOLGADGET,
	(APTR)&DownArrowImage,NULL,NULL,NULL,NULL,22,NULL
};

static struct Image UpArrowImage = {
	0,0,18,12,2,UpArrowData,0x0001,0x0000,NULL
};

static struct Gadget UpArrowGad = {
	&DownArrowGad,406,12,18,12,
	GADGIMAGE,RELVERIFY|GADGIMMEDIATE,BOOLGADGET,
	(APTR)&UpArrowImage,NULL,NULL,NULL,NULL,21,NULL
};

/*
  Disse gadgeten ligge bak teksten i vislistevinduet og brukes for å finne
  ut hvilken post som skal vises i hovedvinduet 
*/
static struct Gadget Linje10 = {
	&UpArrowGad,6,114,395,10,NULL,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,9,NULL
};
static struct Gadget Linje9 = {
	&Linje10,6,104,395,10,NULL,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,8,NULL
};
static struct Gadget Linje8 = {
	&Linje9,6,94,395,10,NULL,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,7,NULL
};
static struct Gadget Linje7 = {
	&Linje8,6,84,395,10,NULL,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,6,NULL
};
static struct Gadget Linje6 = {
	&Linje7,6,74,395,10,NULL,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,5,NULL
};
static struct Gadget Linje5 = {
	&Linje6,6,64,395,10,NULL,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,4,NULL
};

static struct Gadget Linje4 = {
	&Linje5,6,54,395,10,NULL,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,3,NULL
};

static struct Gadget Linje3 = {
	&Linje4,6,44,395,10,NULL,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,2,NULL
};

static struct Gadget Linje2 = {
	&Linje3,6,34,395,10,NULL,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,1,NULL
};

static struct Gadget Linje1 = {
	&Linje2,6,24,395,10,NULL,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,0,NULL
};

/* NewWindow definisjon av vislistevinduet */

static struct NewWindow listnw = {
	0,126,430,130,0,1,
	MOUSEMOVE|GADGETDOWN|GADGETUP|CLOSEWINDOW|MENUPICK|INTUITICKS,
	WINDOWCLOSE|WINDOWDRAG|WINDOWDEPTH,
	&Linje1,NULL,NULL,NULL,NULL,639,70,640,-1,WBENCHSCREEN
};

static UBYTE nbuff[61];
static UBYTE tbuff[22];
static struct IntuiText navntext = {2,1,JAM2,10,25,NULL,nbuff,NULL};
static struct IntuiText tlftext = {2,1,JAM2,305,25,NULL,tbuff,&navntext};

/**************************************************************************/
/* denne rutinen skiver ut navnenen i listen fra en bestem posisjon */

void show_liste(liste)
register struct Liste *liste;
{
	register struct Liste *p;
	register int i,y;

/* hvis listen blir oppdatert setter vi topp til begynnelsen av listen */
	if ( topp != liste) {
		offset = 0;
		topp = p = liste;
	}
	else
		p = liste;

 	for (i=0,y=0;i<10;i++,y += 10) { /* en linje hver 10'ende pixel */
		if (p) {
/* kopier navnet og telefonnummeret over i nbuff og tbuff */

			strcpy(nbuff,p->Navn);
			strcpy(tbuff,p->Telefon);

/* sørg for at nbuff og tbuff alltid er like lang som max antall tegn */

			strcat(nbuff,"                              ");
			strcat(tbuff,"          ");
			nbuff[29] = 0;
			tbuff[10] = 0;
			p = p->neste;
		}
		else {
/*
  slett resten av linjene dersom det ikke er nok poster
  i listen til å dekke alle linjer i vinduet
*/
			strcpy(nbuff,"                              ");
			strcpy(tbuff,"          ");
		}

		PrintIText(lw->RPort,&tlftext,0,y); /* skriv en linje i vinduet */
	}
}

/**************************************************************************/
/*
  denne rutinen justerer proposjonalgadgeten
  når vi har forandret listen eller bruker pilene over.
*/

static void adjustprop(pos)
int pos;
{
/* hvis det er flere en 10 poster må vi kunne skrolle opp og ned */

	if (antall>10) {

/* beregn størrelse på skroll gadget med hensyn til antal poster i listen */

		ScrollGadInfo.VertBody = (MAXBODY / antall) * 10;
		if(ScrollGadInfo.VertBody <KNOBVMIN)
			ScrollGadInfo.VertBody = KNOBVMIN;
	}
/*
  hvis det er mindre en 10 poster i listen settes størrelsen på
  skroll gadgeten til full (ikke flyttbar).
*/
	else
		ScrollGadInfo.VertBody = MAXBODY;

/* sjekk verdier
	if (antall) {
		if(pos > (antall - 10))
			pos = antall - 10;
	}
	else
		pos = 0;

/* beregn posisjon til skrollgadgeten relativt til antall poster i listen */

	if (antall > 10)
		ScrollGadInfo.VertPot = (pos * MAXBODY) / (antall - 10);
	else
		ScrollGadInfo.VertPot = 0;
		
/* juster gadgeten med nye verdier */

	ModifyProp(&ScrollGad,lw,NULL,ScrollGadInfo.Flags,
				ScrollGadInfo.HorizPot,ScrollGadInfo.VertPot,
				ScrollGadInfo.HorizBody,ScrollGadInfo.VertBody);
}

/**************************************************************************/
/* denne rutinene finner ut hvor mange poster det er i listen */

void finnantall(hode)
struct Liste *hode;
{
	register struct Liste *p;

	antall = 0;		/* initialiser antall til 0 */
	p = topp = hode;	/* sett topp peker og teller peker til start av listen */

/* tell alle poster i listen fra begynnelse til slutt */
	while (p) {
		antall++;		/* øk antall med en for hver post */
		p = p->neste;	/* gå til neste post */
	}

	offset = 0;			/* sett offset til start av listen */
	adjustprop(offset); /* juster proposjonal gadgeten i forhold til antallet */
}

/**************************************************************************/
/*
  finn posisjon til proposjonalgadgeten
  posten i toppen av vinduet er posisjonen i listen
*/
void sjekkposisjon(hode)
register struct Liste *hode;
{
	register struct Liste *p;
	register int x,oldoff;

	oldoff = offset; /* ta vare på gammle offset */

/* regn ut ny posisjon for offset med hensyn til antall poster i listen */

	offset = (antall - 10) * ScrollGadInfo.VertPot / MAXBODY;

/* pass på at verdien ikke er ulovlig */

	if (offset > (antall - 10))
		offset = antall - 10;
	else if(offset < 0)
		offset = 0;

/* hvis vi ikke har beveget oss avbryter vi med en gang */

	if ((x = oldoff - offset) == 0)
		return;

/* finn ut hvor hvilken post som blir på toppen av visliste vinduet */

	p = topp;
	if(x < 0) { /* bruker beveget gadgeten nedover */
		for (;x;x++)
			if (p->neste)
				p=p->neste;
			else
				break;
	}
	else {	/* bruker beveget gadgeten oppover */
		for (;x;x--) {
			if (p->forrige)
				p=p->forrige;
			else
				break;
		}
			
	}
/* sett ny topp post */
	topp = p;

/* oppdater tekst i vinduet */
	show_liste(topp); /* skriv listen fra ny topp posisjon */
}

/**************************************************************************/
/* skroll listen ett hakk opp eller ned */

void scroll_up_down(rt)
register short rt;
{
	if (rt == SCROLLUP) { /* vi skal skrolle oppover */
		if (offset > 0  && topp->forrige != NULL) { /* hvis vi er på topp avbryter vi */
			offset--;				/* minsk toppoffset med 1 */
			adjustprop(offset);		/* juster prop. gadget opp */
			topp = topp->forrige;		/* topp peker settes til forrige post */
			show_liste(topp);		/* oppdater tekst i vinduet */
		}
	}
	else if (rt == SCROLLDOWN) { /* vi skal skrolle nedover */
		if ((offset < (antall - 10)) && (topp->neste != NULL)) { /* hvis vi er i på bunnen avbryter vi */
			offset++;				/* øk offset med 1 */
			adjustprop(offset);		/* juster prop. gadget ned */
			topp = topp->neste;		/* topp peker settes til neste post */
			show_liste(topp);		/* oppdater tekst i vinduet */
		}
	}
}

/**************************************************************************/
/*
  finn posisjon på det navnet vi trykker på i vislistevinduet
  og returner posten posisjonen tilsvarer
*/
struct Liste *vislpost(hode,cnt)
register struct Liste *hode; /* liste hode */
register short cnt;			/* GadgetID til gadget bak teksten */
{
	register struct Liste *p;
	register int x;

	p = topp; /* vi starter med posten på toppen av vinduet */

	if (p) {
/*
  Vi holder rede på hvilken posisjon i listen som er toppen av
  vislistevinduet, med den kan vi regne ut hvilken post som skal vises
  i hovedvinduet når en av gadgetene bak teksten er trykket ned.
  Loopen går fra topp posten til den posten som er trykket
*/
		for (x=cnt;x;x--)
			if(p->neste)
				p = p->neste;
			else 
				goto nopost;

		return(p); /* returner funnet post */
	}
nopost:
	return(NULL); /* Ikke noe navn over gadgeten, ingen post å returnere */
}

/**************************************************************************/
/*
  Åpne listevinduet og tegn bakgrunn
  eller slå av vinduet dersom det er på
*/
void visliste(liste,gad,vliste)
struct Liste *liste;
struct Gadget *gad;
char *vliste;
{
	if (lw) { /* hvis vinduet er åpent slåes det av */
		ClearMenuStrip(lw);			/* fjern menyen fra vinduet */
		CloseWindow(lw);			/* lukk vinduet */
		strcpy(vliste,"Liste På");	/* ny tekst i VisListeGad */
		RefreshGadgets(gad,w,NULL);	/* Oppdater VisListeGad med ny tekst */
		lw = NULL;
	}
	else{ /* hvis det ikke er åpent åpner vi det */
		lw = OpenWindow(&listnw); 	/* Åpne visliste vinduet */
		finnantall(liste);			/* finn antall poster i listen */

		if (lw) {
/* tegn bakgrunn og rammer for vislistevinduet */

			strcpy(vliste,"Liste Av"); 	/* ny tekst i VisListeGad */
			RefreshGadgets(gad,w,NULL); /* Oppdater VisListeGad med ny tekst */
			SetAPen(lw->RPort,1);		/* set pen farge til 1 (hvit) */
			SetDrMd(lw->RPort,JAM1);	/* set tegne modus */
			RectFill(lw->RPort,4,11,lw->Width-5,lw->Height-3);	/* fyll vinduet med farge 1 (hvit) */
			RefreshGadgets(&UpArrowGad,lw,NULL); /* oppdater gadgeten i vinduet */
			SetAPen(lw->RPort,2);		/* set pen til 2 (sort) */
			Move(lw->RPort,142,20);		/* flytt tegneposisjon */
			Text(lw->RPort,"Navn",4);	/* skrive overskrift for første kolonne */
			Move(lw->RPort,318,20);		/* flytt tegneposisjon */
			Text(lw->RPort,"Telefon",7);/* skriv overskrift for kolonne 2 */
			DrawBorder(lw->RPort,&vlistborder,0,0); /* tegn ramme rundt kolonnene */
			topp = liste;				/* sett topp pekerne til første post i listen */
			show_liste(topp);			/* skriv ut listen i vinduet */
		}
	}
}
