//============================================================================
//----------------------------------------------------------------------------
//								   RectUtils.c
//----------------------------------------------------------------------------
//============================================================================



#include "Externs.h"
#include "RectUtils.h"



//==============================================================  Functions
//--------------------------------------------------------------  FrameWHRect
// Given the top left corner and a width and height, this functionÉ
// simply creates the necessary rectangle and frames it.

void FrameWHRect (DrawSurface *surface, short left, short top, short wide, short high, PortabilityLayer::ResolveCachingColor &color)
{
	Rect		theRect;
	
	theRect.left = left;
	theRect.top = top;
	theRect.right = left + wide;
	theRect.bottom = top + high;
	surface->FrameRect(theRect, color);
}

//--------------------------------------------------------------  NormalizeRect
// This function ensures that a rect's top is less than it's bottomÉ
// and that left is less than right.

Boolean NormalizeRect (Rect *theRect)
{
	short		tempSide;
	Boolean		changed = false;
	
	if (theRect->left > theRect->right)
	{
		tempSide = theRect->left;
		theRect->left = theRect->right;
		theRect->right = tempSide;
		changed = true;
	}
	
	if (theRect->top > theRect->bottom)
	{
		tempSide = theRect->top;
		theRect->top = theRect->bottom;
		theRect->bottom = tempSide;
		changed = true;
	}

	return changed;
}

//--------------------------------------------------------------  ZeroRectCorner
// The rect passed in is slid over so that its top left corner isÉ
// at coordinates (0, 0).

void ZeroRectCorner (Rect *theRect)		// Offset rect to (0, 0)
{
	theRect->right -= theRect->left;
	theRect->bottom -= theRect->top;
	theRect->left = 0;
	theRect->top = 0;
}

//--------------------------------------------------------------  CenterRectOnPoint
// Given a rectangle and a point, this function centers the rectangleÉ
// on that point.

void CenterRectOnPoint (Rect *theRect, Point where)
{
	ZeroRectCorner(theRect);
	QOffsetRect(theRect, -HalfRectWide(theRect), -HalfRectTall(theRect));
	QOffsetRect(theRect, where.h, where.v);
}

//--------------------------------------------------------------  HalfRectWide
// Given a rectangle, this function returns the rect's width divided by 2.

short HalfRectWide (Rect *theRect)
{
	return ((theRect->right - theRect->left) / 2);
}

//--------------------------------------------------------------  HalfRectTall
// Given a rectangle, this function returns the rect's height divided by 2.

short HalfRectTall (Rect *theRect)
{
	return ((theRect->bottom - theRect->top) / 2);
}

//--------------------------------------------------------------  RectWide
// Given a rectangle, this simple function returns the rect's width.

short RectWide (Rect *theRect)
{
	return (theRect->right - theRect->left);
}

//--------------------------------------------------------------  RectTall
// Given a rectangle, this simple function returns the rect's height.

short RectTall (Rect *theRect)
{
	return (theRect->bottom - theRect->top);
}


//--------------------------------------------------------------  CenterRectInRect
// Given two rectangles, this function centers the first rectangleÉ
// within the second.  The second rect is unchanged.

void CenterRectInRect (Rect *rectA, Rect *rectB)
{
	short	widthA, tallA;
	
	widthA = RectWide(rectA);
	tallA = RectTall(rectA);
	
	rectA->left = rectB->left + (RectWide(rectB) - widthA) / 2;
	rectA->right = rectA->left + widthA;
	
	rectA->top = rectB->top + (RectTall(rectB) - tallA) / 2;
	rectA->bottom = rectA->top + tallA;
}

//--------------------------------------------------------------  HOffsetRect

// Just a simple function to offset a rectangle horizontally only.

void HOffsetRect (Rect *theRect, short h)
{
	theRect->left += h;
	theRect->right += h;
}

//--------------------------------------------------------------  VOffsetRect

// Just a simple function to offset a rectangle vertically only.

void VOffsetRect (Rect *theRect, short v)
{
	theRect->top += v;
	theRect->bottom += v;
}

//--------------------------------------------------------------  IsRectLeftOfRect

// Given two rects, this function returns true if the first rectangleÉ
// is to the left of the second.

Boolean IsRectLeftOfRect (Rect *rect1, Rect *rect2)
{
	short		offset;
	
	offset = (rect1->right - rect1->left) - (rect2->right - rect2->left) / 2;
	if ((rect1->left) < (rect2->left + offset))
		return (true);
	else
		return (false);
}

//--------------------------------------------------------------  QOffsetRect

// This duplicates a Mac ToolBox call, but since it's local, it's faster.
// It offsets a rectangle both vertically and horizontally.

void QOffsetRect (Rect *theRect, short h, short v)
{
	theRect->right += h;
	theRect->left += h;
	theRect->bottom += v;
	theRect->top += v;
}

//--------------------------------------------------------------  QSetRect

// This also duplicates a ToolBox call.  It's needed often though, soÉ
// any gains in speed are nice.  It sets up a rect structure.

void QSetRect (Rect *theRect, short l, short t, short r, short b)
{
	theRect->left = l;
	theRect->top = t;
	theRect->right = r;
	theRect->bottom = b;
}

//--------------------------------------------------------------  ForceRectInRect
// Given a source rectangle and a bounding rectangle, this functionÉ
// will clip the source rect so that it is entirely within the boundingÉ
// rect.  It returns true if any clippiung was necessary.

Boolean ForceRectInRect (Rect *small, Rect *large)
{
	SInt16		hOff, vOff;
	Boolean		changed;
	
	changed = false;
	
	if (NormalizeRect(small))
		changed = true;
	
	if ((small->bottom - small->top) > (large->bottom - large->top))
	{
		small->bottom = small->top + (large->bottom - large->top);
		changed = true;
	}
	
	if ((small->right - small->left) > (large->right - large->left))
	{
		small->right = small->left + (large->right - large->left);
		changed = true;
	}
	
	hOff = large->left - small->left;
	if (hOff > 0)
	{
		OffsetRect(small, hOff, 0);
		changed = true;
	}
	hOff = large->right - small->right;
	if (hOff < 0)
	{
		OffsetRect(small, hOff, 0);
		changed = true;
	}
	vOff = large->top - small->top;
	if (vOff > 0)
	{
		OffsetRect(small, 0, vOff);
		changed = true;
	}
	vOff = large->bottom - small->bottom;
	if (vOff < 0)
	{
		OffsetRect(small, 0, vOff);
		changed = true;
	}
	
	return changed;
}

//--------------------------------------------------------------  QUnionSimilarRect

// Given 2 rects that are assumed to have the same width and height,É
// this function returns a 3rd rect that is the union of those two.

void QUnionSimilarRect (Rect *rectA, Rect *rectB, Rect *rectC)
{
	if (rectA->left < rectB->left)
		rectC->left = rectA->left;
	else
		rectC->left = rectB->left;
	
	if (rectA->top < rectB->top)
		rectC->top = rectA->top;
	else
		rectC->top = rectB->top;
	
	if (rectA->right > rectB->right)
		rectC->right = rectA->right;
	else
		rectC->right = rectB->right;
	
	if (rectA->bottom > rectB->bottom)
		rectC->bottom = rectA->bottom;
	else
		rectC->bottom = rectB->bottom;
}
