/* LWB.C Copyright 1991 by 	
					Joerg Wesemann
					Auf der Heide 12
					W - 2807 Achim - Baden
					Germany
					e-mail: b15l@dhbrrz41.bitnet (prefered)
							joergw@informatik.uni-bremen.de

   Read LWB.DOC for distribution rules !
*/				




#include <exec/types.h>
#include <clib/exec_protos.h>
#include <intuition/intuition.h>
#include <clib/intuition_protos.h>
#include <graphics/gfx.h>
#include <graphics/gfxmacros.h>
#include <clib/graphics_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/dos_protos.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>


struct GfxBase *GfxBase=NULL;
struct IntuitionBase *IntuitionBase=NULL;
struct Library *GadToolsBase=NULL;

struct Window *win=NULL;		/* MiniWB-Window  */
struct Screen *scrbuf = NULL;	/* Daten des Workbench-Screens  */
struct Window *winptr = NULL;	/* Fuer die Windowliste des Screens  */

WORD screenw = 1500;			/* Groesse des WorkbenchScreen  */
WORD screenh = 1000;			/*              -"-             */

WORD xoff = 0;					/* Offsets des Workbench-Screens  */
WORD yoff = 0;					/*                -"-             */

BYTE wxoffset = 0;				/* Window Border offset  */
BYTE wyoffset = 0;

WORD inw = 80;					/* Innenweite des MiniWB-Windows   */		
WORD inh = 0;					/* zu errechnende Innenhoehe -"-   */

WORD winw = 0;					/* Gesamtweite des MiniWB-Windows  */
WORD winh = 0;					/* Gesamthoehe         -"-         */

WORD vieww = 712;				/* Tatsaechlicher sichtbarer Ausschnitt  */
WORD viewh = 512;				/*                  -"-                  */
WORD correcting = 0;			/* Korrekturwert fuer andere Hertzzahlen */

double xmul = 0.0;				/* linearer Umrechnungsfaktor x  */
double ymul = 0.0;				/* linearer Umrechnungsfaktor y  */

SHORT imsgMouseX = 0;			/* Intuition Message Mouse x Koordinate  */
SHORT imsgMouseY = 0;			/* Intuition Message Mouse y Koordinate  */



/* Prototypes */
static void cleanExit( int, char * );
static void updateData( void );
static void okPoint( SHORT *, SHORT *);
static void showView( WORD, WORD, int);
static void relFillRectangle( struct RastPort *, long, long, long, long);
static void relRectangle( struct RastPort *, long, long, long, long);

#ifdef DEBUG
	static void printScreenData(struct Screen *);
	static void printWindowData(struct Window *);
#endif





void updateData(void) 
{   
	double wbxy = 0.0; /* Verhaeltnis WB-Hoehe zu WB-Breite */
	
  	if( ! GetScreenData(scrbuf, sizeof(struct Screen), WBENCHSCREEN,NULL) ) {
		cleanExit(20,"Keine SCREEN-Daten zu bekommen");
	}
	
	#ifdef DEBUG
		printScreenData(scrbuf);
	#endif

	wbxy = (double) screenh / (double) screenw;	
	inh = (WORD) (wbxy * (double) inw);
	
	viewh = scrbuf->Height-correcting;
	vieww = scrbuf->Width;	

    if(win) CloseWindow(win); 		/*  Wenn offen, dann schliessen  */

	xoff = scrbuf->LeftEdge;
	yoff = scrbuf->TopEdge;

	if(!(win=OpenWindowTags(NULL,			WA_InnerWidth,inw,
											WA_InnerHeight,inh,
											WA_Left, vieww-winw-xoff-1,
											WA_Top, viewh-winh-yoff-2,
											WA_Activate,FALSE,
											WA_DragBar,TRUE,
											WA_RMBTrap,TRUE,
											WA_DepthGadget,TRUE,
											WA_CloseGadget,TRUE,
											WA_SizeGadget,FALSE,
											WA_SmartRefresh,TRUE,
											WA_ReportMouse,TRUE,
											WA_IDCMP,IDCMP_CLOSEWINDOW|IDCMP_MOUSEBUTTONS|IDCMP_ACTIVEWINDOW|IDCMP_INACTIVEWINDOW,
											WA_MinWidth,30,
											WA_MinHeight,20,
											WA_Title,"LWB",
										TAG_DONE)))
	cleanExit(20,"OpenWindow() failed");


	winw = win->Width;
	winh = win->Height;
	wxoffset = win->BorderLeft+2;
	wyoffset = win->BorderTop+2;

	MoveWindow(win,vieww - xoff - winw - win->LeftEdge-1 , 
			       viewh - yoff - winh - win->TopEdge-2    );

	#ifdef DEBUG
		printf("Window Move:  x = %d   y= %d\n",vieww - xoff - winw - win->LeftEdge,
												viewh - yoff - winh - win->TopEdge   );
	#endif

  	if( ! GetScreenData(scrbuf, sizeof(struct Screen), WBENCHSCREEN,NULL) ) {
		cleanExit(20,"Keine SCREEN-Daten zu bekommen");
	}

	xmul = ( (double) inw - 4) / (double) screenw;
	ymul = ( (double) inh -4) / (double) screenh;
	
	winptr = scrbuf->FirstWindow;
	while(winptr) {  
		#ifdef DEBUG
			printWindowData(winptr);
		#endif
		if(strcmp("LWB",winptr->Title) && winptr->Width!=screenw) {
			relFillRectangle(win->RPort,winptr->LeftEdge,winptr->TopEdge, winptr->LeftEdge + winptr->Width,winptr->TopEdge+winptr->Height);
		}
		winptr = winptr->NextWindow;
	}
	showView(xoff,yoff,1);
}

void main(int argc,char *argv[])
{
	int ende  = 0;
	int ende2 = 0;
	struct IntuiMessage *imsg;
	ULONG imsgClass;
	UWORD imsgCode,topborder;
	SHORT oldmousex = 0;
	SHORT oldmousey = 0;
	WORD  oldxoff	= 0;
	WORD  oldyoff 	= 0;

	
	if(argc!=3 && argc!=4) 
		cleanExit(20,"Usage:  LWB <vitual_width> <virtual_height> [<correcting>]");

	screenw = (WORD) atoi(argv[1]);
	screenh = (WORD) atoi(argv[2]);
	if (argc==4)
		correcting = atoi(argv[3]);
	else
		correcting = 0;

	if(screenw==0 || screenh==0) 
		cleanExit(20,"Parameter nicht korrekt");

	if(!(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",36L)))
		cleanExit(20,"Brauche V36 graphics.library");

	if(!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",36L)))
		cleanExit(20,"Brauche V36 intuition.library");

	if(!(GadToolsBase=(struct Library *)OpenLibrary("gadtools.library",36L)))
		cleanExit(20,"Brauche V36 gadtools.library");

	if (!(scrbuf = (struct Screen *) malloc(sizeof(struct Screen)) ) )
		cleanExit(20,"Kein temporärer Speicher für SCREEN-Daten");

	onbreak(abort);
	updateData();
	
	while(!ende) {
		chkabort();

		Delay(25);
		
	  	if( ! GetScreenData(scrbuf, sizeof(struct Screen), WBENCHSCREEN,NULL) ) {
			cleanExit(20,"Keine SCREEN-Daten zu bekommen");
		}
				
		if (xoff!= scrbuf->LeftEdge || yoff!= scrbuf->TopEdge) {
			updateData();
		}

		while((!ende) && (imsg= (struct IntuiMessage *) GT_GetIMsg(win->UserPort)) )
		{
			imsgClass=imsg->Class;
			imsgCode=imsg->Code;
			imsgMouseX = imsg->MouseX - wxoffset;
			imsgMouseY = imsg->MouseY - wyoffset;

			GT_ReplyIMsg(imsg);

			switch(imsgClass)
			{	
				case IDCMP_ACTIVEWINDOW:
					WindowToFront(win);
					break;
				case IDCMP_INACTIVEWINDOW:
					break;
				case IDCMP_CLOSEWINDOW:
					ende = 1;
					break;
				case IDCMP_MOUSEBUTTONS:
					if( imsgCode == MENUDOWN ) {
						updateData();
					}
					else if( imsgCode == SELECTDOWN ) {
						showView(xoff,yoff,0); /* altes uebermalen  */
						ModifyIDCMP(win,IDCMP_MOUSEBUTTONS|IDCMP_MOUSEMOVE);
						Wait(1 << win->UserPort->mp_SigBit);
						ende2 = 0;
						oldmousex = imsgMouseX; /* Werte sichern  */
						oldmousey = imsgMouseY;
						while((!ende2)) {
							while( imsg=(struct IntuiMessage *) GT_GetIMsg(win->UserPort)) {
								imsgClass=imsg->Class;
								imsgCode=imsg->Code;
								imsgMouseX = imsg->MouseX - wxoffset;
								imsgMouseY = imsg->MouseY - wyoffset;

								GT_ReplyIMsg(imsg);

								switch(imsgClass) {
									case IDCMP_MOUSEBUTTONS:
										if(imsgCode==SELECTUP) {
											okPoint(&imsgMouseX,&imsgMouseY);
											MoveScreen(win->WScreen,imsgMouseX-xoff,imsgMouseY-yoff); 
											ende2 = 1;
										}
										break;
									case IDCMP_MOUSEMOVE:
										showView(xoff - (WORD) ( (double) ( imsgMouseX - oldmousex ) / xmul ), 
												 yoff - (WORD) ( (double) ( imsgMouseY - oldmousey ) / ymul ), 0 );
								
										break;
								}
							} /* of while GetMsg() */
						} /* while(!ende2) */ 
						updateData();
					}
					break;
				default:
					break;	
			}
		}
	}
  
	cleanExit(0,NULL);
}


void cleanExit(int rc,char *msg)
{
	if(win)
		CloseWindow(win);
		win = NULL;
	if(scrbuf)
		free(scrbuf);
		scrbuf = NULL;

	if(IntuitionBase)
		CloseLibrary(IntuitionBase);
		IntuitionBase = NULL;

	if(GfxBase)
		CloseLibrary(GfxBase);
		GfxBase= NULL;

	if(rc)
		puts(msg);
	exit(rc);	
}


static void relFillRectangle( struct RastPort *rp, long xl, long yo, long xr, long yu)
{
	xl = (long) (xmul * (double) xl ) + wxoffset;
	yo = (long) (ymul * (double) yo ) + wyoffset;
	xr = (long) (xmul * (double) xr ) + wxoffset;
	yu = (long) (ymul * (double) yu ) + wyoffset;
	
	SetAPen(rp,2);
	RectFill(rp,xl,yo,xr,yu);
	SetAPen(rp,1);
	Move(rp,xl,yo);
	Draw(rp,xr,yo);
	Draw(rp,xr,yu);
	Draw(rp,xl,yu);
	Draw(rp,xl,yo);	
}


static void relRectangle( struct RastPort *rp, long xl, long yo, long xr, long yu)
{
	xl = (long) (xmul * (double) xl ) + wxoffset;
	yo = (long) (ymul * (double) yo ) + wyoffset;
	xr = (long) (xmul * (double) xr ) + wxoffset;
	yu = (long) (ymul * (double) yu ) + wyoffset;
	
	SetAPen(rp,1);
	Move(rp,xl,yo);
	Draw(rp,xr,yo);
	Draw(rp,xr,yu);
	Draw(rp,xl,yu);
	Draw(rp,xl,yo);	
}


/* DICE spezifische Abbruchfunktion  */
void abort(void)
{
	cleanExit(1,"CTRL_C gedrueckt");
}


static void okPoint(SHORT *x , SHORT *y)
	/* erhaelt den geklickten Punkt und verwandelt diesen in die 
	   korrekte Start-Koordinate des neuen Fensters
	*/
{
	SHORT dxl = 0;
	SHORT dxr = 0;
	SHORT dxu = 0;
	SHORT dxo = 0;
	

	/* nach Workbench-Window transformieren  */
	
	*x = (SHORT) ( (double) *x / xmul );
	*y = (SHORT) ( (double) *y / ymul );	

	dxl = *x - vieww / 2;
	dxr = *x + vieww / 2;
	dxu = *y + viewh / 2;
	dxo = *y - viewh / 2;

	/* Horizontaler Test  */
	if( dxl < 0 ) {
		*x -= dxl;
	}
	else if (dxr > screenw) {
		*x -= (dxr - screenw);
	}
	/* Vertikaler Test   */
	if( dxo < 0) {
		*y -= dxo;
	}
	else if (dxu > screenh) {
		*y -= (dxu - screenh);
	}
	
	*x -= vieww / 2;
	*y -= viewh / 2;

	*x *= -1;
	*y *= -1;

}


static void showView(WORD xoff, WORD yoff, int first)
{	
	static WORD xold = 0;		/* alter xoffset  */
	static WORD yold = 0;		/* alter yoffset  */

	if(xoff>0) {
		xoff = 0;
	}
	else if (xoff < -screenw + vieww) {
		xoff = -screenw + vieww;
	}

	if(yoff>0) {
		yoff = 0;
	}
	else if (yoff < -screenh + viewh) {
		yoff = -screenh + viewh;
	}
	
	SetDrPt(win->RPort,0x5555);	
	SetAPen(win->RPort,1);

	if(!first) {				/* altes loeschen  */
		SetDrMd(win->RPort,COMPLEMENT);

		relRectangle(win->RPort,-xold,-yold,-xold+vieww,-yold+viewh);
		SetDrMd(win->RPort,JAM1);
	}
	
	SetDrMd(win->RPort,COMPLEMENT);

	relRectangle(win->RPort,-xoff,-yoff,-xoff+vieww,-yoff+viewh);

	SetDrMd(win->RPort,JAM1);
	SetDrPt(win->RPort,0xffff);

	xold = xoff;
	yold = yoff;
}


#ifdef DEBUG

static void printScreenData(struct Screen *s)
{
	printf("\nScreen:\nNextScreen: %d  FirstWindow: %d\n",s->NextScreen,s->FirstWindow);
	printf("LeftEdge: %d    TopEdge: %d    Width: %d    Height: %d\n",s->LeftEdge,s->TopEdge,s->Width,s->Height);
	printf("Title: %s   DefaultTitle: %s\n",s->Title,s->DefaultTitle);
	printf("\n");
}

static void printWindowData(struct Window *w)
{
	printf("\nWindow:\nScreen: %d   NextWindow: %d\n",w->WScreen,w->NextWindow);
	printf("LeftEdge:  %d    TopEdge:   %d    Width: %d    Height: %d\n",w->LeftEdge,w->TopEdge,w->Width,w->Height);
	printf("MinWidth:  %d    MaxWidth:  %d\n",w->MinWidth,w->MaxWidth);
	printf("MinHeight: %d    MaxHeight: %d\n",w->MinHeight,w->MaxHeight);
	printf("Title: %s \n",w->Title);
	printf("\n");
}
#endif
