/********************************************************************
 *																	*
 *	WinLIB PRO Revision II: Extended AES segment					*
 *																	*
 *	Copyright (C) 1994, Bitgate Software							*
 *																	*
 ********************************************************************/

#include <stddef.h>
#include <string.h>
#include "winlib.h"

#ifndef __XAES__
#define __XAES__
#endif

/* Fixed linepattern stuff by putting the animation in an
   array instead. This is really pretty stupid, since a simple
   680x0 ROL instruction would rotate the pattern as we wanted
   to. C kinda sucks sometimes. -KA */
int linepatterns[] = {0x7FF8, 0x3FFC, 0x1FFE, 0x0FFF, 0x87FF, 0xC3FF, 0xE1FF, 0xF0FF,
					  0xF87F, 0xFC3F, 0xFE1F, 0xFF0F, 0xFF87, 0xFFC3, 0xFFE1, 0xFFF0};

/*
 *	Drag or move a custom designed box
 *	Written by Ken Hollis
 *
 *	width, height, beginx, beginy = beginning rectangle coordinates
 *	boundx, boundy, boundw, boundh = rectangle boundaries
 *	linecolor = color of line to draw
 *	linetype = type of line to draw
 *	linepattern = pattern of line if custom line
 *	*endx, *endy = ending coordinates (x, y) of box
 *	animate = flag for internal line drawing animation
 *
 *	Boundaries can be switched on or off at will.  For instance, if
 *	the programmer doesn't want an X boundary, it is defined as -1,
 *	the Y boundary is the same, and so are all other variables,
 *	respectively.  Only those ENABLED variables are the ones that
 *	are used.
 *
 *	It's a bit messy, but everything's commented, so there should be
 *	no problems.
 */
GLOBAL void WDragBox(int width, int height, int beginx, int beginy,
			int boundx, int boundy, int boundw, int boundh,
			int linecolor, int linetype, int linepattern,
			int *endx, int *endy, int animate)
{
	int mx = 0, my = 0, button, dummy, origx, origy, cntr = 0, xo,
		yo, dx = 0, dy = 0;
	int attributes[6], modeattributes[10], pxy[20], fillattributes[5];
	int linepat = 0;
	GRECT pos;

	/* Clear out the ending values for now */
	*endx = 0;
	*endy = 0;

	/* Get line and graphics mode attributes */
	vql_attributes(VDIhandle, attributes);
	vqt_attributes(VDIhandle, modeattributes);
	vqf_attributes(VDIhandle, fillattributes);

	/* Get the original position of the mouse at startup */
	graf_mkstate(&origx, &origy, &dummy, &dummy);

	/* Remove clipping for now (yes, this HAS to be done!) */
	pxy[0] = desk.g_x;
	pxy[1] = desk.g_y;
	pxy[2] = desk.g_x + desk.g_w;
	pxy[3] = desk.g_y + desk.g_h;

	vs_clip(VDIhandle, 1, pxy);

	/* Set attributes */
	vsl_color(VDIhandle, linecolor);
	if (animate) {
		vsl_type(VDIhandle, USERLINE);
		vsl_udsty(VDIhandle, linepatterns[linepat]);
	} else
		if (linetype == USERLINE) {
			vsl_type(VDIhandle, USERLINE);
			vsl_udsty(VDIhandle, linepattern);
		} else
			vsl_type(VDIhandle, linetype);
		
	vswr_mode(VDIhandle, MD_XOR);

	pos.g_x = beginx;
	pos.g_y = beginy;
	pos.g_w = width;
	pos.g_h = height;

	WGrafMouse(M_OFF);

	pxy[0] = pxy[6] = pxy[8] = pos.g_x;
	pxy[1] = pxy[3] = pxy[9] = pos.g_y;
	pxy[2] = pxy[4] = pos.g_x + pos.g_w;
	pxy[5] = pxy[7] = pos.g_y + pos.g_h;
	v_pline(VDIhandle, 5, pxy);

	WGrafMouse(M_ON);

	do {
		/* Store the mouse positions */
		xo = mx;
		yo = my;

		/* Get mouse coordinates and button state */
		graf_mkstate(&mx, &my, &button, &dummy);

		/* Calculate the mouse movement difference */
		dx = mx - xo;
		dy = my - yo;

		/* Increase the animation-pause step counter */
		cntr++;

		if (!animate) {
			if (dx || dy)
				WGrafMouse(M_OFF);	/* Turn off the mouse */
		} else
			WGrafMouse(M_OFF);

		/* Draw the original box to erase it (remember MD_XOR) */
		pxy[0] = pxy[6] = pxy[8] = pos.g_x;
		pxy[1] = pxy[3] = pxy[9] = pos.g_y;
		pxy[2] = pxy[4] = pos.g_x + pos.g_w;
		pxy[5] = pxy[7] = pos.g_y + pos.g_h;
		Vsync();
		v_pline(VDIhandle, 5, pxy);

		/* Let the new box equal the mouse position minus the offset
           so it's positioned to where the mouse was first clicked */
		pos.g_x = beginx + (mx - origx);
		pos.g_y = beginy + (my - origy);

		/* Check the width boundary of the box */
		if (boundw != -1) {
			int tx;

			/* Find the offset from the width boundary */
			if ((tx = (pos.g_x + pos.g_w) - (boundw)) < 0)
				tx = 0;
			else
				tx += 1;

			/* And reposition the x offset of the drawn box */
			pos.g_x -= tx;
		}

		/* Check the height boundary of the box */
		if (boundh != -1 && boundy != -1) {
			int ty;

			/* Find the offset from the height boundary */
			if ((ty = (pos.g_y + pos.g_h) - (boundy + boundh)) < 0)
				ty = 0;
			else
				ty += 1;

			/* And reposition the y offset of the drawn box */
			pos.g_y -= ty;
		}

		/* Check the x boundary of the box */
		if (boundx != -1)
			if (pos.g_x < boundx)
				pos.g_x = boundx;

		/* Check the y boundary of the box */
		if (boundy != -1)
			if (pos.g_y < boundy)
				pos.g_y = boundy;

		/* Check animation pause counter */
		if (cntr == 1) {
			cntr = 0;	/* Reset the counter */

			if (animate) {
				linepat = (linepat + 1) & 0xf;
				vsl_udsty(VDIhandle, linepatterns[linepat]);
			}
		}

		/* Draw the new box at the new coordinates */
		pxy[0] = pxy[6] = pxy[8] = pos.g_x;
		pxy[1] = pxy[3] = pxy[9] = pos.g_y;
		pxy[2] = pxy[4] = pos.g_x + pos.g_w;
		pxy[5] = pxy[7] = pos.g_y + pos.g_h;
		v_pline(VDIhandle, 5, pxy);
		Vsync();

		if (!animate) {
			if (dx || dy)
				WGrafMouse(M_ON);	/* Turn on the mouse */
		} else WGrafMouse(M_ON);
	} while (button);

	/* Turn off the mouse again */
	WGrafMouse(M_OFF);

	/* Erase the box so it doesn't show anymore */
	pxy[0] = pxy[6] = pxy[8] = pos.g_x;
	pxy[1] = pxy[3] = pxy[9] = pos.g_y;
	pxy[2] = pxy[4] = pos.g_x + pos.g_w;
	pxy[5] = pxy[7] = pos.g_y + pos.g_h;
	v_pline(VDIhandle, 5, pxy);

	/* And turn on the mouse */
	WGrafMouse(M_ON);

	/* Reset the clipping rectangle at its original place, just in
	   case it happened to have been this.  Won't hurt anything. */
	pxy[0] = beginx;
	pxy[1] = beginy;
	pxy[2] = width;
	pxy[3] = height;

	vs_clip(VDIhandle, 1, pxy);

	/* Restore all drawing modes */
	vsl_color(VDIhandle, attributes[1]);
	vsl_type(VDIhandle, attributes[0]);
	vsl_udsty(VDIhandle, 0xFFFF);
	vst_color(VDIhandle, modeattributes[1]);
	vswr_mode(VDIhandle, modeattributes[5]);
	vsf_color(VDIhandle, fillattributes[1]);
	vsf_interior(VDIhandle, fillattributes[0]);
	vsf_style(VDIhandle, fillattributes[2]);

	/* and return the ending values */
	*endx = pos.g_x;
	*endy = pos.g_y;
}

GLOBAL void WGraf_Rubberbox(int bx, int by, int linecolor, int linetype, int linepattern,
			int *endx, int *endy, int animate)
{
	int mx, my, button, dummy, origx, origy, cntr = 0,
		boundx, boundy, boundw, boundh;
	int attributes[6], modeattributes[10], pxy[20], fillattributes[5];
	int linepat = 0;
	GRECT pos;

	*endx = 0;
	*endy = 0;

	vql_attributes(VDIhandle, attributes);
	vqt_attributes(VDIhandle, modeattributes);
	vqf_attributes(VDIhandle, fillattributes);

	graf_mkstate(&origx, &origy, &dummy, &dummy);

	pxy[0] = desk.g_x;
	pxy[1] = desk.g_y;
	pxy[2] = desk.g_x + desk.g_w;
	pxy[3] = desk.g_y + desk.g_h;

	vs_clip(VDIhandle, 1, pxy);

	vsl_color(VDIhandle, linecolor);
	if (animate) {
		vsl_type(VDIhandle, USERLINE);
		vsl_udsty(VDIhandle, linepatterns[linepat]);
	} else
		if (linetype == USERLINE) {
			vsl_type(VDIhandle, USERLINE);
			vsl_udsty(VDIhandle, linepattern);
		} else
			vsl_type(VDIhandle, linetype);
		
	vswr_mode(VDIhandle, MD_XOR);

	pos.g_x = bx;
	pos.g_y = by;
	pos.g_w = 0;
	pos.g_h = 0;

	WGrafMouse(M_OFF);

	pxy[0] = pxy[6] = pxy[8] = pos.g_x;
	pxy[1] = pxy[3] = pxy[9] = pos.g_y;
	pxy[2] = pxy[4] = pos.g_x + pos.g_w;
	pxy[5] = pxy[7] = pos.g_y + pos.g_h;
	v_pline(VDIhandle, 5, pxy);

	WGrafMouse(M_ON);

	boundx = desk.g_x;
	boundy = desk.g_y;
	boundw = desk.g_w;
	boundh = desk.g_h;

	do {
		graf_mkstate(&mx, &my, &button, &dummy);

		cntr++;

		WGrafMouse(M_OFF);

		pxy[0] = pxy[6] = pxy[8] = pos.g_x;
		pxy[1] = pxy[3] = pxy[9] = pos.g_y;
		pxy[2] = pxy[4] = pos.g_x + pos.g_w;
		pxy[5] = pxy[7] = pos.g_y + pos.g_h;
		Vsync();
		v_pline(VDIhandle, 5, pxy);

		pos.g_w = mx - pos.g_x;
		pos.g_h = my - pos.g_y;

		if (boundw!=-1) {
			int tx;

			if ((tx = (pos.g_x + pos.g_w) - (boundw)) < 0)
				tx = 0;
			else
				tx += 1;

			pos.g_x -= tx;
		}

		if (boundh != -1 && boundy != -1) {
			int ty;

			if ((ty = (pos.g_y + pos.g_h) - (boundy + boundh)) < 0)
				ty = 0;
			else
				ty += 1;

			pos.g_y -= ty;
		}

		if (boundx != -1)
			if (pos.g_x < boundx)
				pos.g_x = boundx;

		if (boundy != -1)
			if (pos.g_y < boundy)
				pos.g_y = boundy;

		if (cntr == 1) {
			cntr = 0;	/* Reset the counter */

			if (animate) {
				linepat = (linepat + 1) & 0xf;
				vsl_udsty(VDIhandle, linepatterns[linepat]);
			}
		}

		pxy[0] = pxy[6] = pxy[8] = pos.g_x;
		pxy[1] = pxy[3] = pxy[9] = pos.g_y;
		pxy[2] = pxy[4] = pos.g_x + pos.g_w;
		pxy[5] = pxy[7] = pos.g_y + pos.g_h;
		v_pline(VDIhandle, 5, pxy);
		Vsync();

		WGrafMouse(M_ON);
	} while (button);

	WGrafMouse(M_OFF);

	pxy[0] = pxy[6] = pxy[8] = pos.g_x;
	pxy[1] = pxy[3] = pxy[9] = pos.g_y;
	pxy[2] = pxy[4] = pos.g_x + pos.g_w;
	pxy[5] = pxy[7] = pos.g_y + pos.g_h;
	v_pline(VDIhandle, 5, pxy);

	WGrafMouse(M_ON);

	vsl_color(VDIhandle, attributes[1]);
	vsl_type(VDIhandle, attributes[0]);
	vsl_udsty(VDIhandle, 0xFFFF);
	vst_color(VDIhandle, modeattributes[1]);
	vswr_mode(VDIhandle, modeattributes[5]);
	vsf_color(VDIhandle, fillattributes[1]);
	vsf_interior(VDIhandle, fillattributes[0]);
	vsf_style(VDIhandle, fillattributes[2]);

	*endx = pos.g_x;
	*endy = pos.g_y;
}