/****************************************************************************/
/*																																					*/
/* SHADOW.C 																																*/
/*																																					*/
/* This program show how to use UltraWin with those pretty 3-d shadowed 		*/
/* windows everyone likes to do.  Just take the routines you want below,    */
/* and put them into your own programs!                                     */
/*                                                                          */
/*                                                         Boyd Gafford			*/
/*                                                         EnQue Software		*/
/*                                                         02/25/92         */
/*																																					*/
/****************************************************************************/
#include <ctype.h>
#include "uw.h"
#include "uw_globx.h"
#include "uw_keys.h"


#define	SH_TOP_LEFT			0								/* used by shadow window functions	*/
#define SH_TOP_RIGHT		1
#define SH_BOTTOM_RIGHT	2
#define	SH_BOTTOM_LEFT	3

#define	NUM_WINDOWS 		15							/* for the popup shadow demo				*/

/*----------------------- global window variables --------------------------*/
WINDOW	Desk_window;                 		/* global window for "desktop"     	*/
WINDOW	Test_window;										/* global POPUP window for demo			*/
WINDOW	Win_array[NUM_WINDOWS];

char		*Test_str =
"Now is the time for all good men to come to the aid of their country.  ";

/*------------------------------ prototypes --------------------------------*/
void shadow_window( WINDOW *wnp, int type, int w, int h, int att );
void unshadow_window( WINDOW *wnp );


/*********/
/* ~main */
/*       ********************************************************************/
/* This is the main function, which does the init stuff and demos the new   */
/* shadow routines.                                                         */
/****************************************************************************/
int main()
{
	WINDOW	*desk_wnp = &Desk_window;
	WINDOW	*test_wnp = &Test_window;
	int 		i, xs, ys, xe, ye, width, height;

	/*---------------------------- init stuff --------------------------------*/
	init_video(80, 25);														/* try an 80xe5 screen			*/
	init_clock(0x3333);														/* init to 91 ticks/second	*/
	init_mouse();																	/* init the mouse						*/
	wn_create(0, 0, V_cols - 1, V_rows - 1,				/* one full-screen window		*/
						NO_BDR, WN_POPUP, desk_wnp);
	wn_color(BLACK, BLUE, desk_wnp);
	wn_bdr_color(BLACK, BLUE, desk_wnp);
	desk_wnp->scroll = OFF;												/* turn off desktop scroll	*/
	wn_set(desk_wnp);															/* put the window on-screen	*/
	for (i=0; i<222; i++)													/* do a little background		*/
	{																							/* to show off the shadow		*/
		wn_color((i % 8) + 8, BLUE, desk_wnp);
		wn_st("UltraWin ", desk_wnp);
	}
	wn_color(BLACK, BLUE, desk_wnp);


	/*---------------------- first, a simple demo ----------------------------*/
	wn_create(7, 10, 72, 15,											/* create the demo window		*/
						SGL_BDR, WN_POPUP, test_wnp);
	wn_color(WHITE, LIGHTGRAY, test_wnp);
	wn_bdr_color(BLACK, LIGHTGRAY, test_wnp);
	wn_name(" Press any key ", test_wnp);

	wn_set(test_wnp);															/* put the window on-screen	*/
	wn_plst(CENTERED, 2,
		"Window without a shadow.", test_wnp);
	wait_event();

	mv_cs(0, 2, test_wnp);												/* show the 4 shadow types	*/
	wn_cleol(test_wnp);
	wn_plst(CENTERED, 2,
		"Low shadowed window.", test_wnp);
	for (i=SH_TOP_LEFT; i<=SH_BOTTOM_LEFT; i++)
	{
		shadow_window(test_wnp, i, 2, 1, DARKGRAY);
		wait_event();
		unshadow_window(test_wnp);
	}

	mv_cs(0, 2, test_wnp);												/* show w and h variances		*/
	wn_cleol(test_wnp);
	wn_plst(CENTERED, 2,
		"High shadowed window.", test_wnp);
	for (i=SH_TOP_LEFT; i<=SH_BOTTOM_LEFT; i++)
	{
		shadow_window(test_wnp, i, 4, 2, DARKGRAY);
		wait_event();
		unshadow_window(test_wnp);
	}

	wn_destroy(test_wnp);													/* destroy the window				*/

	/*----------------------- now, lets go crazy! ----------------------------*/
	for ( i = 0; i < NUM_WINDOWS; i++ )
	{
		width = random(20) + 15;
		height = random(3) + 4;
		xs = random(V_cols - width - 1);
		ys = random(V_rows - height - 1);
		xe = xs + width - 1;
		ye = ys + height - 1;
		wn_create(xs, ys, xe, ye, SGL_BDR, WN_POPUP, &Win_array[i]);
		wn_color((i % 8) + 8, i % 8, &Win_array[i]);
		wn_bdr_color((i % 8) + 8, i % 8, &Win_array[i]);
	}
	for ( i = 0; i < NUM_WINDOWS; i++ )
	{
		wn_set(&Win_array[i]);
		shadow_window(&Win_array[i], SH_BOTTOM_RIGHT, 2, 1, DARKGRAY);
		wn_st(Test_str, &Win_array[i]);
		wn_st(Test_str, &Win_array[i]);
	}
	wait_event();
	for( i = NUM_WINDOWS - 1; i >= 0; i-- )
	{
		unshadow_window(&Win_array[i]);
		wn_destroy(&Win_array[i]);
	}

	/*------------------------- termination stuff ----------------------------*/
	wn_destroy(desk_wnp);													/* destroy the desk window	*/
	end_mouse();																	/* terminate the mouse			*/
	end_video();																	/* back to old video mode		*/
	return(1);																		/* exit the progarm					*/
}
/*** end of main ***/

/******************/
/* ~shadow_window */
/*                ***********************************************************/
/* This routine takes the window passed by pointer and shadows it.  It does */
/* this by creating sub windows using the usr_ptr member of the window      */
/* structure.                                                               */
/*                                                                          */
/* The contents under these sub windows are read off the screen and put 		*/
/* inside the windows.  The attribute is then changed and the window is			*/
/* placed on the screen, giving the illusion of a shadow.                   */
/*                                                                          */
/* You may pass this routine a width, height and attribute (DARKGRAY on  		*/
/* BLACK with a width of 2 and height of 1 usually looks nice).             */
/* You may also pass a type, which is a number from 0-3 (see #defines) that */
/* indicates the direction the shadow falls.                                */
/*                                                                          */
/* The main thing to remember is be SURE that you call the unshadow_window	*/
/* function BEFORE you destroy the window, or else you will have heap  			*/
/* problems.                                             										*/
/****************************************************************************/
void shadow_window( WINDOW *wnp, int type, int w, int h, int att )
{
	WINDOW 	*wnp1, *wnp2;													/* shadow window pointers		*/
	int			xs = wnp->pane.x_min;									/* get the screen coords		*/
	int			ys = wnp->pane.y_min;
	int			xe = wnp->pane.x_max;
	int			ye = wnp->pane.y_max;
	int			win1_xs, win1_ys, win1_xe, win1_ye;
	int			win2_xs, win2_ys, win2_xe, win2_ye;
	int			i;
	uchar		*dest;

	if (wnp->usr_ptr == NULL)
	{
		switch(type)
		{
			case SH_TOP_LEFT:
				win1_xs = xs - w, win1_ys = ys - h;			/* left side of window	 		*/
				win1_xe = xs - 1, win1_ye = ye - h;
				win2_xs = xs    , win2_ys = ys - h;			/* top side of window				*/
				win2_xe = xe - w, win2_ye = ys - 1;
				break;
			case SH_TOP_RIGHT:
				win1_xs = xe + 1, win1_ys = ys - h;			/* right side of window	 		*/
				win1_xe = xe + w, win1_ye = ye - h;
				win2_xs = xs + w, win2_ys = ys - h;			/* top side of window				*/
				win2_xe = xe    , win2_ye = ys - 1;
				break;
			case SH_BOTTOM_LEFT:
				win1_xs = xs - w, win1_ys = ys + h;			/* left side of window	 		*/
				win1_xe = xs - 1, win1_ye = ye + h;
				win2_xs = xs    , win2_ys = ye + 1;			/* bottom side of window		*/
				win2_xe = xe - w, win2_ye = ye + h;
				break;
			default:
				win1_xs = xe + 1, win1_ys = ys + h;			/* right side of window	 		*/
				win1_xe = xe + w, win1_ye = ye + h;
				win2_xs = xs + w, win2_ys = ye + 1;			/* bottom side of window		*/
				win2_xe = xe    , win2_ye = ye + h;
				break;
		}
		wnp->usr_ptr = calloc(1, sizeof(WINDOW));		/* alloc/create first win		*/
		wn_create(win1_xs, win1_ys, win1_xe, win1_ye,
							NO_BDR, WN_POPUP,
							(WINDOW *) wnp->usr_ptr);
		wnp1 = (WINDOW *) wnp->usr_ptr;
		wn_read(wnp1);
		dest = wnp1->buff + 1;											/* set to DARKGRAY on BLACK	*/
		for (i=0; i<(wnp1->cols * wnp1->rows); i++)
			*dest = att, dest += 2;

		wnp1->usr_ptr = calloc(1, sizeof(WINDOW));	/* alloc/create second win	*/
		wn_create(win2_xs, win2_ys, win2_xe, win2_ye,
							NO_BDR, WN_POPUP,
							(WINDOW *) wnp1->usr_ptr);
		wnp2 = (WINDOW *) wnp1->usr_ptr;
		wn_read(wnp2);
		dest = wnp2->buff + 1;											/* set to DARKGRAY on BLACK	*/
		for (i=0; i<(wnp2->cols * wnp2->rows); i++)
			*dest = att, dest += 2;

		wn_save(wnp1), wn_rfsh(wnp1);								/* do the wn_set equivalent	*/
		wn_save(wnp2), wn_rfsh(wnp2);
	}
}
/*** end of shadow_window ***/

/********************/
/* ~unshadow_window */
/*                  *********************************************************/
/*  This is the complement to shadow_window.  You MUST call this function   */
/* before you destroy the window that has been shadowed or you will have		*/
/* severe problems.  If you don't it will have the same effect as not 			*/
/* calling win_destroy on a created window.  Your computer will lockup!			*/
/****************************************************************************/
void unshadow_window( WINDOW *wnp )
{
	WINDOW 	*wnp1, *wnp2;													/* shadow window pointers		*/

	if (wnp->usr_ptr)                             /* does it have a shadow?		*/
	{
		wnp1 = (WINDOW *) wnp->usr_ptr;							/* get the window pointers	*/
		wnp2 = (WINDOW *) wnp1->usr_ptr;
		wn_destroy(wnp2), wn_destroy(wnp1);
		free(wnp2), free(wnp1);											/* and free the structure		*/
		wnp->usr_ptr = NULL;
	}
}
/*** end of unshadow_window ***/

/*** END OF FILE ***/