;/*
sc ignore=73 OPTIMIZE OPTSIZE OPTGO OPTPEEP NOSTKCHK Zoom!.c
slink from lib:c.o Zoom!.o to /Zoom! LIB LIB:sc.lib LIB:amiga.lib SC SD ND NOICONS STRIPDEBUG
delete Zoom!.o
quit

*/

#include <exec/memory.h>
#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfx.h>
#include <dos/dos.h>
#include <devices/timer.h>
#include <3AM/libraries/bitmap.h>
#include <stdio.h>
#include <string.h>

#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#include <3AM/clib/bitmap_protos.h>
#include <3AM/pragmas/bitmap_pragmas.h>

UWORD chip Lens_data[] = {
0x0000, 0x0000, 0x0000, 0x0700, 0x0700, 0x1FC0, 0x18C0, 0x37E0, 0x3060, 0x68B0, 0x2020, 0x5070,
0x4010, 0xA038, 0x4010, 0xA038, 0x4010, 0xA038, 0x2020, 0x5050, 0x3060, 0x48B0,
0x18F0, 0x2718, 0x0738, 0x18CC, 0x001C, 0x0726, 0x000E, 0x0013, 0x0004, 0x000E,
0x0000, 0x0004, 0x0000, 0x0000 };

UWORD chip SPlus_data[] = {
0x7FFF,0xC000,0x7FFF,0xC000,0x7F3F,0xC000,0x7F3F,0xC000,0x7807,0xC000,0x7F3F,0xC000,
0x7F3F,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0xFFFF,0x8000,0xFE1F,0x8000,
0xFEDF,0x8000,0xF0C3,0x8000,0xF7FB,0x8000,0xF0C3,0x8000,0xFEDF,0x8000,0xFE1F,0x8000,
0xFFFF,0x8000,0x8000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 };

UWORD chip SMinus_data[] = {
0x7FFF,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0x7807,0xC000,0x7FFF,0xC000,
0x7FFF,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0xFFFF,0x8000,0xFFFF,0x8000,
0xFFFF,0x8000,0xF003,0x8000,0xF7FB,0x8000,0xF003,0x8000,0xFFFF,0x8000,0xFFFF,0x8000,
0xFFFF,0x8000,0x8000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 };

UWORD chip SAutoPlus_data[] = {
0x7FFF,0xC000,0x7FFF,0xC000,0x767F,0xC000,0x66FF,0xC000,0x67E7,0xC000,0x7081,0xC000,
0x7FE7,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0xFFFF,0x8000,0xF07F,0x8000,
0xEFBF,0x8000,0xDFC3,0x8000,0xDF18,0x8000,0xEF7E,0x8000,0xF018,0x8000,0xFFC3,0x8000,
0xFFFF,0x8000,0x8000,0x0000 };

UWORD chip SAutoMinus_data[] = {
0x7FFF,0xC000,0x7FFF,0xC000,0x767F,0xC000,0x66FF,0xC000,0x67BF,0xC000,0x70FF,0xC000,
0x7F81,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0xFFFF,0x8000,0xF07F,0x8000,
0xEFBF,0x8000,0xDFDF,0x8000,0xDFDF,0x8000,0xEF00,0x8000,0xF07E,0x8000,0xFF00,0x8000,
0xFFFF,0x8000,0x8000,0x0000 };

struct Image SPlus_image = { 0,0,18,10,3,SPlus_data,7,0,0 };
struct Image SMinus_image = { 0,0,18,10,3,SMinus_data,7,0,0 };
struct Image SAutoPlus_image = { 0,0,18,10,2,SAutoPlus_data,3,0,0 };
struct Image SAutoMinus_image = { 0,0,18,10,2,SAutoMinus_data,3,0,0 };

#define ZOOM_IN_GDG_ID	1
#define ZOOM_OUT_GDG_ID	2
#define AUTO_PLUS_GDG_ID 3
#define AUTO_MINUS_GDG_ID 4

struct Gadget ZoomInGdg = {
	NULL, -17, 0, 18, 10, GFLG_RELRIGHT | GFLG_GADGHCOMP | GFLG_GADGIMAGE,
	GACT_RELVERIFY | GACT_RIGHTBORDER, GTYP_BOOLGADGET, &SPlus_image, NULL, NULL, 0L, NULL, ZOOM_IN_GDG_ID, NULL };

struct Gadget ZoomOutGdg = {
	&ZoomInGdg, -17, 0, 18, 10, GFLG_RELRIGHT | GFLG_GADGHCOMP | GFLG_GADGIMAGE,
	GACT_RELVERIFY | GACT_RIGHTBORDER, GTYP_BOOLGADGET, &SMinus_image, NULL, NULL, 0L, NULL, ZOOM_OUT_GDG_ID, NULL };

struct Gadget AutoPlusGdg = {
	&ZoomOutGdg, -17, 0, 18, 10, GFLG_RELRIGHT | GFLG_GADGHCOMP | GFLG_GADGIMAGE,
	GACT_RELVERIFY | GACT_RIGHTBORDER, GTYP_BOOLGADGET, &SAutoPlus_image, NULL, NULL, 0L, NULL, AUTO_PLUS_GDG_ID, NULL };

struct Gadget AutoMinusGdg = {
	&AutoPlusGdg, -17, 0, 18, 10, GFLG_RELRIGHT | GFLG_GADGHCOMP | GFLG_GADGIMAGE,
	GACT_RELVERIFY | GACT_RIGHTBORDER, GTYP_BOOLGADGET, &SAutoMinus_image, NULL, NULL, 0L, NULL, AUTO_MINUS_GDG_ID, NULL };

struct NewWindow nwt = {
	60, 60, 142, 75, 0, 0, IDCMP_CLOSEWINDOW | IDCMP_MOUSEBUTTONS | IDCMP_GADGETUP | IDCMP_NEWSIZE,
	WFLG_ACTIVATE | WFLG_SIZEGADGET | WFLG_SIZEBRIGHT | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET | WFLG_RMBTRAP,
	&AutoMinusGdg, NULL, NULL, NULL, NULL, 120, 61, 0, 0, WBENCHSCREEN };

#define PROGRAM_NAME "Zoom! v1.5"
#define AUTHORS_NAME "Stefano Reksten"

char *version = "$VER: Zoom! v1.5 (3.9.95) by Stefano Reksten";

char *SCR_NAME = PROGRAM_NAME" © 1995 by "AUTHORS_NAME;
char *WND_NAME = PROGRAM_NAME" - S:00 - A:00";

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *BitMapBase, *IconBase;
struct Window *window;

struct BitMap *destBm;
struct BitMapScaleInfo *sinfo;
struct MsgPort *TimerMP;
struct timerequest *TimerIO;
ULONG time_delay;
BOOL timer_running = FALSE;

UWORD height, width, lastX, lastY;
UBYTE depth, scaling_factor = 2;

struct BitMapScaleInfo bsi;


void FreeBitMaps( void )
{
if ( destBm )
	DisposeBitMap( destBm );
}


BOOL AllocBitMaps( void )
{
width = ( window->Width - window->BorderLeft - window->BorderRight ) / scaling_factor;
height = ( window->Height - window->BorderTop - window->BorderBottom ) / scaling_factor;

destBm = CreateBitMap( (width+1) * scaling_factor, (height+1) * scaling_factor, depth );

if ( destBm )
	return TRUE;
else
	return FALSE;
}


void Zoom( void )
{
register UWORD X = lastX;
register UWORD Y = lastY;

UWORD w = width * scaling_factor / 2;
UWORD h = height * scaling_factor / 2;

UWORD sw = window->WScreen->Width;
UWORD sh = window->WScreen->Height;

if ( X > w/scaling_factor )
	X -= w/scaling_factor;
else	X = 0;

if ( X > sw - width )
	X = sw - width;

if ( Y > h/scaling_factor )
	Y -= h/scaling_factor;
else	Y = 0;

if ( Y > sh - height )
	Y = sh - height;

RectFill( window->RPort, window->BorderLeft, window->BorderTop, window->Width - window->BorderRight, window->Height - window->BorderBottom );
bsi.bsi_HorNum = scaling_factor;
bsi.bsi_VertNum = scaling_factor;
bsi.bsi_Width = width;
bsi.bsi_Height = height;
bsi.bsi_SrcLeftEdge = X;
bsi.bsi_SrcTopEdge = Y;
bsi.bsi_DestLeftEdge = /*window->LeftEdge + window->BorderLeft;*/0;
bsi.bsi_DestTopEdge = /*window->TopEdge + window->BorderTop;*/0;
ScaleBitMap( &bsi );
BltBitMapRastPort( destBm, 0, 0, window->RPort, window->BorderLeft, window->BorderTop, width * scaling_factor, height * scaling_factor, 0xC0 );
}


BOOL SetUpTimer( void )
{
if ( TimerMP = CreateMsgPort() )
	{
	if ( TimerIO = (struct timerequest *)CreateExtIO(TimerMP, sizeof( struct timerequest ) ) )
		{
		if ( !(OpenDevice( "timer.device", UNIT_VBLANK, (struct IORequest *)TimerIO, 0 ) ) )
			{
			TimerIO->tr_node.io_Command = TR_ADDREQUEST;
			TimerIO->tr_time.tv_secs = time_delay;
			SendIO( (struct IORequest *)TimerIO );
			return( TRUE );
			}
		DeleteExtIO( (struct IORequest *)TimerIO );
		}
	DeleteMsgPort( TimerMP );
	}
return( FALSE );
}


void RemoveTimer( void )
{
if ( TimerIO )
	{
	if ( !( CheckIO( (struct IORequest *)TimerIO ) ) )
		AbortIO( (struct IORequest *)TimerIO );
	WaitIO( (struct IORequest *)TimerIO );
	CloseDevice( (struct IORequest *)TimerIO );
	DeleteExtIO( (struct IORequest *)TimerIO );
	DeletePort( TimerMP );
	TimerIO = NULL;
	}
}


void SetTitles( void )
{
WND_NAME[15] = '0' + scaling_factor / 10;
WND_NAME[16] = '0' + scaling_factor % 10;

if ( !time_delay )
	{
	WND_NAME[22] = 'N';
	WND_NAME[23] = 'A';
	}
else
	{
	if ( time_delay < 100 )
		{
		WND_NAME[22] = '0' + time_delay / 10;
		WND_NAME[23] = '0' + time_delay % 10;
		}
	else
		{
		WND_NAME[22] = '?';
		WND_NAME[23] = '!';
		}
	}

SetWindowTitles( window, WND_NAME, SCR_NAME );
}

void ProcessMessages( void )
{
register BOOL stay = TRUE;
register ULONG signal, mask = 1L<<window->UserPort->mp_SigBit | SIGBREAKF_CTRL_C;
register struct IntuiMessage *msg;
register struct Message *timerMsg;
register struct Gadget *gdg;
register ULONG class;
register UWORD code;

while( stay )
	{
	if ( timer_running )
		mask |= 1L<<TimerMP->mp_SigBit;

	signal = Wait ( mask );

	if ( signal & SIGBREAKF_CTRL_C )
		stay = FALSE;

	if ( timer_running && signal & 1L<<TimerMP->mp_SigBit )
		{
		if ( timerMsg = GetMsg( TimerMP ) )
			{
			Zoom();
			TimerIO->tr_node.io_Command = TR_ADDREQUEST;
			TimerIO->tr_time.tv_secs = time_delay;
			SendIO( (struct IORequest *)TimerIO );
			}
		}

	if ( signal & 1L<<window->UserPort->mp_SigBit )
		{
		while ( msg = (struct IntuiMessage *)GetMsg( window->UserPort ) )
			{
			class = msg->Class;
			code = msg->Code;

			switch( class )
				{
				case IDCMP_CLOSEWINDOW:
					stay = FALSE;
					break;
				case IDCMP_NEWSIZE:
					FreeBitMaps();
					width = ( window->Width - window->BorderLeft - window->BorderRight -1 ) / scaling_factor;
					height = ( window->Height - window->BorderTop - window->BorderBottom -1 ) / scaling_factor;
					if ( stay = AllocBitMaps() )
						Zoom();
					break;
				case IDCMP_MOUSEBUTTONS:
					switch( code )
						{
						case MENUUP:
							lastX = IntuitionBase->MouseX;
							lastY = IntuitionBase->MouseY;
							if ( !( window->WScreen->ViewPort.Modes & LACE ) )
								lastY >>= 1;
							if ( (window->WScreen->ViewPort.Modes & SUPERHIRES ) )
								lastX <<= 1;
							else
							if ( !(window->WScreen->ViewPort.Modes & HIRES ) )
								lastX >>= 1;
 							Zoom();
							break;
						default:
							break;
						}
					break;
				case IDCMP_GADGETUP:
					gdg = (struct Gadget *)msg->IAddress;
					if ( gdg->GadgetID == ZOOM_IN_GDG_ID && scaling_factor < 40 )
						{
						FreeBitMaps();
						scaling_factor++;
						width = ( window->Width - window->BorderLeft - window->BorderRight -1 ) / scaling_factor;
						height = ( window->Height - window->BorderTop - window->BorderBottom -1 ) / scaling_factor;
						if ( stay = AllocBitMaps() )
							Zoom();
						}
					else
					if ( gdg->GadgetID == ZOOM_OUT_GDG_ID && scaling_factor > 2 )
						{
						FreeBitMaps();
						scaling_factor--;
						width = ( window->Width - window->BorderLeft - window->BorderRight -1 ) / scaling_factor;
						height = ( window->Height - window->BorderTop - window->BorderBottom -1 ) / scaling_factor;
						if ( stay = AllocBitMaps() )
							Zoom();
						}
					else
					if ( gdg->GadgetID == AUTO_PLUS_GDG_ID )
						{
						time_delay++;
						if ( timer_running == FALSE )
							{
							if ( timer_running = SetUpTimer() )
								OnGadget( &AutoMinusGdg, window, NULL );
							}
						}
					else
					if ( gdg->GadgetID == AUTO_MINUS_GDG_ID )
						{
						if ( time_delay && timer_running )
							{
							time_delay--;
							RemoveTimer();
							if ( !time_delay )
								{
								timer_running = FALSE;
								OffGadget( &AutoMinusGdg, window, NULL );
								}
							else	SetUpTimer();
							}
						}
					SetTitles();
					break;
				default:
					break;
				}
			ReplyMsg( (struct Message *)msg );
			}
		}
	}
}


void main( int argc, char *argv[] )
{
if ( argc )
	{
	LONG args[6];
	struct RDArgs *rdargs;

	memset( args, 0, 24 );
	if ( rdargs = ReadArgs( "Auto/N,Scale/N,Left/N,Top/N,Width/N,Height/N", args, NULL ) )
		{
		if ( args[0] ) { time_delay = *((ULONG *)args[0]); timer_running = TRUE; }
		if ( args[1] ) scaling_factor = *((ULONG *)args[1]);
		if ( args[2] ) nwt.LeftEdge = *((ULONG *)args[2]);
		if ( args[3] ) nwt.TopEdge = *((ULONG *)args[3]);
		if ( args[4] ) nwt.Width = *((ULONG *)args[4]);
		if ( args[5] ) nwt.Height = *((ULONG *)args[5]);
		FreeArgs( rdargs );
		}
	}
else
if ( IconBase = OpenLibrary( "icon.library", 0L ) )
	{
	char **ttypes = ArgArrayInit( argc, argv );

	if ( time_delay = ArgInt( ttypes, "AUTO", 0 ) )
		timer_running = TRUE;
	scaling_factor = ArgInt( ttypes, "SCALE", 2 );
	if ( scaling_factor < 2 || scaling_factor > 40 )
		scaling_factor = 2;
	nwt.LeftEdge = ArgInt( ttypes, "WLEFT", 60 );
	nwt.TopEdge = ArgInt( ttypes, "WTOP", 60 );
	nwt.Width = ArgInt( ttypes, "WWIDTH", 142 );
	nwt.Height = ArgInt( ttypes, "WHEIGHT", 75 );

	ArgArrayDone();
	CloseLibrary( IconBase );
	}

if ( IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library", 0L ) )
	{
	if ( GfxBase = (struct GfxBase *)OpenLibrary( "graphics.library", 0L ) )
		{
		if ( BitMapBase = OpenLibrary( "bitmap.library", 0L ) )
			{
			struct Screen *pubscr = LockPubScreen( NULL );
			if ( pubscr )
				{
				depth = pubscr->RastPort.BitMap->Depth;

				ZoomInGdg.TopEdge = pubscr->Font->ta_YSize + 3;
				ZoomOutGdg.TopEdge = ZoomInGdg.TopEdge + 10;
				AutoPlusGdg.TopEdge = ZoomOutGdg.TopEdge + 10;
				AutoMinusGdg.TopEdge = AutoPlusGdg.TopEdge + 10;

				nwt.MaxWidth = pubscr->Width;
				nwt.MaxHeight = pubscr->Height;

				if ( window = OpenWindow( &nwt ) )
					{
					SetTitles();
					SetAPen( window->RPort, 0 );
					SetPointer( window, Lens_data, 16L, 16L, -6, -6 );

					if ( AllocBitMaps() )
						{
						bsi.bsi_SrcBitMap = pubscr->RastPort.BitMap;
						bsi.bsi_DestBitMap = /*bsi.bsi_SrcBitMap;*/destBm;
						bsi.bsi_TempBitMap = NULL;
						bsi.bsi_HorDen = 1;
						bsi.bsi_VertDen = 1;
						bsi.bsi_Flags = NULL;

						if ( timer_running )
							timer_running = SetUpTimer();
						if ( !timer_running || !time_delay )
							OffGadget( &AutoMinusGdg, window, NULL );
						lastX = 0;
						lastY = 0;
						Zoom();
						ProcessMessages();
						FreeBitMaps();
						if ( timer_running )
							RemoveTimer();
						}
					ClearPointer( window );
					CloseWindow( window );
					}
				UnlockPubScreen( NULL, pubscr );
				}
			CloseLibrary( BitMapBase );
			}
		CloseLibrary( (struct Library *)GfxBase );
		}
	CloseLibrary( (struct Library *)IntuitionBase );
	}
}
