/************************************************************/
/*                                                          */
/* Sample source for STICKS screen saver for Intermission   */
/*                                                          */
/* Copyright (C) 1990-1991 Anthony Andersen                 */
/*                                                          */
/* All rights reserved.                                     */
/*                                                          */
/* The author grants permission for registered owners of    */
/* Intermission to modify this code to create new screen    */
/* savers and to distribute the modified savers freely.     */
/* This sample code is only legally available to registered */
/* users of Intermission.                                   */
/*                                                          */
/************************************************************/

#include <windows.h>
#include "sticks.h"

/* ID of dialog item to hold "Sticks before erase" value */

#define IDD_VALUE     5

unsigned long seed;  /* for random number generator                     */
char buffer[10];     /* general purpose character buffer                */
unsigned erasecount; /* how many "sticks" to draw before erasing screen */

RECT rect;           /* rectangle of saver window                       */
HBRUSH hbrush;       /* handle to BLACK_BRUSH stock object              */
unsigned count;      /* number of "sticks" already drawn                */
unsigned colormax;   /* highest color index                             */

char savername[]   = "Sticks";      /* values for retrieving profile data */
char key2name[]    = "Num Sticks";
char profilename[] = "ANTSW.INI";

/* this is called by the default dll entry code during the  */
/* load library call - always happens BEFORE any other call */
/* in the dll. the library is loaded and unloaded quite     */
/* often so don't allocate anything that takes much time.   */

int FAR PASCAL LibMain(hModule, wDataSeg, cbHeapSize, lpszCmdLine)

HANDLE	hModule;
WORD     wDataSeg;
WORD     cbHeapSize;
LPSTR    lpszCmdLine;

{

   /* set up things here */

	/* if your profile data has minimum or maximum values, you should */
	/* do error checking and fix the values here.                     */

	erasecount = GetPrivateProfileInt(savername,key2name,250,profilename);

	return (1);
}


/* this is called by Windows when the dll is released */

int FAR PASCAL WEP (bSystemExit)
int  bSystemExit;

{
    /* get rid of things you allocated in the LibMain proc here */

    return (1);
}

/* this is called (probably lots of times) by Intermission */
/* be careful not to allocate memory or objects here       */

char FAR * FAR PASCAL saverinit(BOOL far *realize)

{
	/* request color palette 1 */

	*realize = 1;

	/* You must return either the saver's name or NULL */

	return(savername);
}

/* dialog proc for user customization */

BOOL FAR PASCAL saverdlgproc(HWND hdlg,unsigned message,WORD wparam,LONG lparam)

{

	#define MINVAL 0          /* minimum acceptable value for erasecount */
	#define MAXVAL 32000      /* maximum acceptable value for erasecount */

	int i;                    /* scrollbar value                         */
	int whichfield;           /* which scrollbar is message from?        */
	int minval;               /* minimum value for current scrollbar     */
	int maxval;               /* maximum value for current scrollbar     */

	switch (message) {

	case WM_INITDIALOG:

		/* set the dialog items */

		SetDlgItemInt(hdlg,IDD_VALUE,erasecount,FALSE);

		/* set scrollbar range and position */

		SetScrollRange(GetDlgItem(hdlg,IDD_VALUE+20),SB_CTL,MINVAL,MAXVAL,FALSE);
		SetScrollPos(GetDlgItem(hdlg,IDD_VALUE+20),SB_CTL,erasecount,FALSE);

		return (TRUE);

	case WM_HSCROLL:

		/* Generic horizontal scrollbar message handler.  */
		/* It is not needed for this saver, but I hope it */
		/* is useful as an example.                       */

		whichfield = GetDlgCtrlID((HWND)(HIWORD(lparam)))-20;
		i = GetDlgItemInt(hdlg,whichfield,NULL,FALSE);

		switch (whichfield) {

		case IDD_VALUE:
			minval = MINVAL;
			maxval = MAXVAL;
			break;

		/* Put other cases here */

		}

		switch (wparam) {

		case SB_LINEDOWN:
			if (i<maxval) i++;
			break;

		case SB_LINEUP:
			if (i>minval) i--;
			break;

		case SB_PAGEDOWN:
			if (i<=maxval-10) i += 10;
			else i = maxval;
			break;

		case SB_PAGEUP:
			if (i>=minval+10) i -= 10;
			else i = minval;
			break;

		case SB_BOTTOM:
			i = maxval;
			break;

		case SB_TOP:
			i = minval;
			break;

		case SB_THUMBTRACK:
		case SB_THUMBPOSITION:
			i = LOWORD(lparam);
			break;

		}

		SetDlgItemInt(hdlg,whichfield,i,FALSE);
		SetScrollPos(GetDlgItem(hdlg,whichfield+20),SB_CTL,i,TRUE);
		break;

	case WM_COMMAND:

		if (wparam == IDOK) {

			/* user pressed OK button - get the new value and save */
			/* it in the profile.                                  */

			erasecount = GetDlgItemInt(hdlg,IDD_VALUE,NULL,FALSE);
			wsprintf(buffer,"%u",erasecount);
			WritePrivateProfileString(savername,key2name,buffer,profilename);

			/* return value parameter to EndDialog doesn't matter */

			EndDialog(hdlg,TRUE);
			return (TRUE);
		}
		else if (wparam == IDCANCEL) {

			/* user pressed Cancel so don't change anything.      */
			/* return value parameter to EndDialog doesn't matter */

			EndDialog(hdlg,FALSE);
			return (TRUE);
		}
		break;

	}

	return (FALSE);
}

/* returns pseudorandom number from 0 to x-1 */

int arand(int x)
{
	seed = seed*0x343fd+0x269ec3;
	return (int)(((seed>>16)&0x7fff)*x>>15);
}

COLORREF makecolor(HPALETTE hpal)

{
	COLORREF cr;

 	cr = arand(224)+32;
	cr = (cr<<8)+arand(224)+32;
	cr = (cr<<8)+arand(224)+32;
	if (hpal) cr = GetNearestPaletteIndex(hpal,cr)+0x1000000;
	else if (colormax == 2) cr = 0x00FFFFFF;

	return (cr);
}

/* the main drawing routine */

VOID FAR PASCAL saverdraw(HWND hwnd,HDC hdc,HANDLE hinst,HPALETTE hpal,int opcode)

{

	int      x1,x2,y1,y2;    /* end points of line */
	HPEN     hpen;           /* pen to draw with   */
	HPEN     hOldPen;        /* old pen from DC    */
	int      pw;             /* pen width          */
	COLORREF cr;             /* pen color index    */
	int      resbits;

	if (!opcode) {

		/* Normal drawing opcode */

		/* black out screen if appropriate */

		if (count == erasecount) {
			count = 0;
			FillRect(hdc,&rect,hbrush);
		}

		/* get "random" color and width */

		cr = makecolor(hpal);
		pw = arand(10);

		hpen = CreatePen(PS_SOLID,pw,cr);

		hOldPen = SelectObject(hdc,hpen);

		/* get "random" coordinates of endpoints of line */

		x1 = arand(rect.right-rect.left)+rect.left;
		x2 = arand(rect.right-rect.left)+rect.left;
		y1 = arand(rect.bottom-rect.top)+rect.top;
		y2 = arand(rect.bottom-rect.top)+rect.top;

		/* draw line */

		MoveTo(hdc,x1,y1);
		LineTo(hdc,x2,y2);

		/* delete pen */

		SelectObject(hdc,hOldPen);
		DeleteObject(hpen);

		count++;
	}

	else if (opcode == 1) {

		/* initialization opcode */

		/* figure out how many colors are available on the device */

		if (GetDeviceCaps(hdc,RASTERCAPS) & RC_PALETTE) {
			colormax = GetDeviceCaps(hdc,SIZEPALETTE);
			if (colormax != 256) colormax = 16;
		}
		else {
			resbits = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
			if (resbits <= 8)	colormax = 1<<(resbits);
			else colormax = 0xFFFF;
		}

		/* the rect will fill the screen */

		GetClipBox(hdc,&rect);

		/* seed the pseudorandom number generator */

		seed = GetTickCount();

		/* get black brush for erasing screen */

		hbrush = GetStockObject(BLACK_BRUSH);

		/* black out screen */

		FillRect(hdc,&rect,hbrush);

		/* set state variable(s) */

		count = 0;
	}

	else if (opcode == 2) {

		/* clean up opcode - free anything allocated or created */
		/* that hasn't already been freed.                      */

	}

}

