/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * The contents of this file are subject to the Netscape Public License
 * Version 1.0 (the "NPL"); you may not use this file except in
 * compliance with the NPL.  You may obtain a copy of the NPL at
 * http://www.mozilla.org/NPL/
 *
 * Software distributed under the NPL is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
 * for the specific language governing rights and limitations under the
 * NPL.
 *
 * The Initial Developer of this code under the NPL is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
 * Reserved.
 */

#ifdef PowerPlant_PCH
#include PowerPlant_PCH
#endif

#include <UMemoryMgr.h>
#include <UDrawingState.h>
#include <UDrawingUtils.h>
#include <UGAColorRamp.h>

#include "UGraphicGizmos.h"
#include "CGWorld.h"

#include "mfinder.h" // needed for workaround function to bug in Appe's
					 // ::TruncText and ::TruncString - andrewb 6/20/97

#ifndef __PALETTES__
#include <Palettes.h>
#endif

#include <string.h>

RGBColor UGraphicGizmos::sLighter = { 0xFFFF, 0xFFFF, 0xFFFF };
RGBColor UGraphicGizmos::sDarker = { 0x0000, 0x0000, 0x0000 };

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	LoadBevelTraits
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::LoadBevelTraits(
	ResIDT 				inBevelTraitsID,
	SBevelColorDesc& 	outBevelDesc)
{
	Assert_(inBevelTraitsID != resID_Undefined);
	
	StResource theBevelResource('BvTr', inBevelTraitsID);
	::BlockMoveData(*(theBevelResource.mResourceH), &outBevelDesc, sizeof(SBevelColorDesc));
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	BevelRect
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::BevelRect(
	const Rect&		inRect,
	Int16 			inBevel,
	Int16 			inTopColor,
	Int16			inBottomColor)
{
	StColorPenState thePenSaver;
	thePenSaver.Normalize();

	Rect theBevelRect = inRect;
	theBevelRect.bottom--;
	theBevelRect.right--;

	StDeviceLoop theLoop(inRect);
	Int16 theDepth;
	while (theLoop.NextDepth(theDepth))
		{
		if (theDepth < 4)
			{
			// Draw a monochrome bevel
			QDGlobals* theQDPtr = UQDGlobals::GetQDGlobals();
			PatPtr theTopPat, theBottomPat;
	
			if (inBevel < 0)
				{
				inBevel = -inBevel;
				theTopPat = &theQDPtr->black;
				theBottomPat = &theQDPtr->white;
				}
			else
				{
				theTopPat = &theQDPtr->white;
				theBottomPat = &theQDPtr->black;
				}
	
			for (Int16 index = 1; index <= inBevel; index++)
				{
				::PenPat(theTopPat);
				::MoveTo(theBevelRect.right, theBevelRect.top);
				::LineTo(theBevelRect.left, theBevelRect.top);
				// 1997-03-24 pkc
				// Don't draw topleft corner twice
				::Move(0, 1);
				::LineTo(theBevelRect.left, theBevelRect.bottom);
				
				::PenPat(theBottomPat);
				::LineTo(theBevelRect.right, theBevelRect.bottom);
				// 1997-03-24 pkc
				// Don't draw bottomright corner twice
				::Move(0, -1);
				::LineTo(theBevelRect.right, theBevelRect.top);
		
				::InsetRect(&theBevelRect, 1, 1);
				}
			}
		else
			{
			// Draw a color bevel
			Int16 theTopColor, theBottomColor;
	
			if (inBevel < 0)
				{
				inBevel = -inBevel;
				theTopColor = inBottomColor;
				theBottomColor = inTopColor;
				}
			else
				{
				theTopColor = inTopColor;
				theBottomColor = inBottomColor;
				}

			for (Int16 index = 1; index <= inBevel; index++)
				{
				::PmForeColor(theTopColor);
				::MoveTo(theBevelRect.right, theBevelRect.top);
				::LineTo(theBevelRect.left, theBevelRect.top);
				// 1997-03-24 pkc
				// Don't draw topleft corner twice
				::Move(0, 1);
				::LineTo(theBevelRect.left, theBevelRect.bottom);
				
				::PmForeColor(theBottomColor);
				::LineTo(theBevelRect.right, theBevelRect.bottom);
				// 1997-03-24 pkc
				// Don't draw bottomright corner twice
				::Move(0, -1);
				::LineTo(theBevelRect.right, theBevelRect.top);
				
				::InsetRect(&theBevelRect, 1, 1);
				}
			}
		}
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	BevelPartialRect
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::BevelPartialRect(
	const Rect&			inRect,
	Int16 				inBevel,
	Int16 				inTopColor,
	Int16				inBottomColor,
	const SBooleanRect&	inSides)
{
	StColorPenState thePenSaver;
	thePenSaver.Normalize();

	Rect theBevelRect = inRect;
	theBevelRect.bottom--;
	theBevelRect.right--;

	for (Int16 index = 1; index <= inBevel; index++)
		{
		::PmForeColor(inTopColor);
		if (inSides.left)
			{
			// 1997-03-24 pkc
			// Don't draw topleft corner twice
			if (inSides.top)
				::MoveTo(theBevelRect.left, theBevelRect.top + 1);
			else
				::MoveTo(theBevelRect.left, theBevelRect.top);
			::LineTo(theBevelRect.left, theBevelRect.bottom);
			}
			
		if (inSides.top)
			{
			::MoveTo(theBevelRect.right, theBevelRect.top);
			::LineTo(theBevelRect.left, theBevelRect.top);
			}

		::PmForeColor(inBottomColor);
		if (inSides.right)
			{
			::MoveTo(theBevelRect.right, theBevelRect.top);
			// 1997-03-24 pkc
			// Don't draw bottomright corner twice
			if (inSides.bottom)
				::LineTo(theBevelRect.right, theBevelRect.bottom - 1);
			else
				::LineTo(theBevelRect.right, theBevelRect.bottom);
			}
			
		if (inSides.bottom)
			{
			::MoveTo(theBevelRect.left, theBevelRect.bottom);
			::LineTo(theBevelRect.right, theBevelRect.bottom);
			}
		
		::InsetRect(&theBevelRect, 1, 1);
		}
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	BevelRect
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::BevelRect(
	const Rect&		inRect,
	Int16 			inBevel,
	const RGBColor&	inTopColor,
	const RGBColor&	inBottomColor)
{
	StColorPenState thePenSaver;
	thePenSaver.Normalize();

	Rect theBevelRect = inRect;
	theBevelRect.bottom--;
	theBevelRect.right--;

	StDeviceLoop theLoop(inRect);
	Int16 theDepth;
	while (theLoop.NextDepth(theDepth))
		{
		if (theDepth < 4)
			{
			// Draw a monochrome bevel
			QDGlobals* theQDPtr = UQDGlobals::GetQDGlobals();
			PatPtr theTopPat, theBottomPat;
	
			if (inBevel < 0)
				{
				inBevel = -inBevel;
				theTopPat = &theQDPtr->black;
				theBottomPat = &theQDPtr->white;
				}
			else
				{
				theTopPat = &theQDPtr->white;
				theBottomPat = &theQDPtr->black;
				}
	
			for (Int16 index = 1; index <= inBevel; index++)
				{
				::PenPat(theTopPat);
				::MoveTo(theBevelRect.right, theBevelRect.top);
				::LineTo(theBevelRect.left, theBevelRect.top);
				// 1997-03-24 pkc
				// Don't draw topleft corner twice
				::Move(0, 1);
				::LineTo(theBevelRect.left, theBevelRect.bottom);
				
				::PenPat(theBottomPat);
				::LineTo(theBevelRect.right, theBevelRect.bottom);
				// 1997-03-24 pkc
				// Don't draw bottomright corner twice
				::Move(0, -1);
				::LineTo(theBevelRect.right, theBevelRect.top);
		
				::InsetRect(&theBevelRect, 1, 1);
				}
			}
		else
			{
			// Draw a color bevel
			RGBColor theTopColor, theBottomColor;
	
			if (inBevel < 0)
				{
				inBevel = -inBevel;
				theTopColor = inBottomColor;
				theBottomColor = inTopColor;
				}
			else
				{
				theTopColor = inTopColor;
				theBottomColor = inBottomColor;
				}

			for (Int16 index = 1; index <= inBevel; index++)
				{
				::RGBForeColor(&theTopColor);
				::MoveTo(theBevelRect.right, theBevelRect.top);
				::LineTo(theBevelRect.left, theBevelRect.top);
				// 1997-03-24 pkc
				// Don't draw topleft corner twice
				::Move(0, 1);
				::LineTo(theBevelRect.left, theBevelRect.bottom);
				
				::RGBForeColor(&theBottomColor);
				::LineTo(theBevelRect.right, theBevelRect.bottom);
				// 1997-03-24 pkc
				// Don't draw bottomright corner twice
				::Move(0, -1);
				::LineTo(theBevelRect.right, theBevelRect.top);
				
				::InsetRect(&theBevelRect, 1, 1);
				}
			}
		}
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	BevelRectAGA
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::BevelRectAGA(
	const Rect&		inRect,
	Int16 			inBevel,
	const RGBColor&	inTopColor,
	const RGBColor&	inBottomColor)
{
	StColorPenState thePenSaver;
	thePenSaver.Normalize();

	Rect theBevelRect = inRect;
	theBevelRect.bottom--;
	theBevelRect.right--;

	StDeviceLoop theLoop(inRect);
	Int16 theDepth;
	while (theLoop.NextDepth(theDepth))
		{
		if (theDepth < 4)
			{
			// Draw a monochrome bevel
			QDGlobals* theQDPtr = UQDGlobals::GetQDGlobals();
			PatPtr theTopPat, theBottomPat;
	
			if (inBevel < 0)
				{
				inBevel = -inBevel;
				theTopPat = &theQDPtr->black;
				theBottomPat = &theQDPtr->white;
				}
			else
				{
				theTopPat = &theQDPtr->white;
				theBottomPat = &theQDPtr->black;
				}
	
			for (Int16 index = 1; index <= inBevel; index++)
				{
				::PenPat(theTopPat);
				::MoveTo(theBevelRect.right - 1, theBevelRect.top);
				::LineTo(theBevelRect.left, theBevelRect.top);
				// 1997-03-24 pkc
				// Don't draw topleft corner twice
				::Move(0, 1);
				::LineTo(theBevelRect.left, theBevelRect.bottom - 1);
				
				::PenPat(theBottomPat);
				::MoveTo(theBevelRect.left + 1, theBevelRect.bottom);
				::LineTo(theBevelRect.right, theBevelRect.bottom);
				// 1997-03-24 pkc
				// Don't draw bottomright corner twice
				::Move(0, -1);
				::LineTo(theBevelRect.right, theBevelRect.top + 1);
		
				::InsetRect(&theBevelRect, 1, 1);
				}
			}
		else
			{
			// Draw a color bevel
			RGBColor theTopColor, theBottomColor;
	
			if (inBevel < 0)
				{
				inBevel = -inBevel;
				theTopColor = inBottomColor;
				theBottomColor = inTopColor;
				}
			else
				{
				theTopColor = inTopColor;
				theBottomColor = inBottomColor;
				}

			for (Int16 index = 1; index <= inBevel; index++)
				{
				::RGBForeColor(&theTopColor);
				::MoveTo(theBevelRect.right - 1, theBevelRect.top);
				::LineTo(theBevelRect.left, theBevelRect.top);
				// 1997-03-24 pkc
				// Don't draw topleft corner twice
				::Move(0, 1);
				::LineTo(theBevelRect.left, theBevelRect.bottom - 1);
				
				::RGBForeColor(&theBottomColor);
				::MoveTo(theBevelRect.left + 1, theBevelRect.bottom);
				::LineTo(theBevelRect.right, theBevelRect.bottom);
				// 1997-03-24 pkc
				// Don't draw bottomright corner twice
				::Move(0, -1);
				::LineTo(theBevelRect.right, theBevelRect.top + 1);
				
				::InsetRect(&theBevelRect, 1, 1);
				}
			}
		}
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	BevelPartialRect
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::BevelPartialRect(
	const Rect&			inRect,
	Int16 				inBevel,
	const RGBColor&		inTopColor,
	const RGBColor&		inBottomColor,
	const SBooleanRect&	inSides)
{
	StColorPenState thePenSaver;
	thePenSaver.Normalize();

	Rect theBevelRect = inRect;
	theBevelRect.bottom--;
	theBevelRect.right--;

	for (Int16 index = 1; index <= inBevel; index++)
		{
		::RGBForeColor(&inTopColor);
		if (inSides.left)
			{
			// 1997-03-24 pkc
			// Don't draw topleft corner twice
			if (inSides.top)
				::MoveTo(theBevelRect.left, theBevelRect.top + 1);
			else
				::MoveTo(theBevelRect.left, theBevelRect.top);
			::LineTo(theBevelRect.left, theBevelRect.bottom);
			}
			
		if (inSides.top)
			{
			::MoveTo(theBevelRect.right, theBevelRect.top);
			::LineTo(theBevelRect.left, theBevelRect.top);
			}

		::RGBForeColor(&inBottomColor);
		if (inSides.right)
			{
			::MoveTo(theBevelRect.right, theBevelRect.top);
			// 1997-03-24 pkc
			// Don't draw bottomright corner twice
			if (inSides.bottom)
				::LineTo(theBevelRect.right, theBevelRect.bottom - 1);
			else
				::LineTo(theBevelRect.right, theBevelRect.bottom);
			}
			
		if (inSides.bottom)
			{
			::MoveTo(theBevelRect.left, theBevelRect.bottom);
			::LineTo(theBevelRect.right, theBevelRect.bottom);
			}
		
		::InsetRect(&theBevelRect, 1, 1);
		}
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	BevelTintPartialRect
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::BevelTintPartialRect(
	const Rect &	inRect,
	Int16 			inBevel,
	Uint16			inTopTint,
	Uint16			inBottomTint,
	const SBooleanRect& inSides)
{
	StColorPenState thePenSaver;
	thePenSaver.Normalize();

	RGBColor theAddColor = { inTopTint, inTopTint, inTopTint };
	RGBColor theSubColor = { inBottomTint, inBottomTint, inBottomTint };

	Rect theBevelRect = inRect;
	theBevelRect.bottom--;
	theBevelRect.right--;

	if (inBevel >= 0)
		{
		::RGBForeColor(&theAddColor);
		::OpColor(&sLighter);
		::PenMode(addPin);
		}
	else
		{
		::RGBForeColor(&theSubColor);
		::OpColor(&sDarker);
		::PenMode(subPin);
		}

	Int16 theBevel = (inBevel >= 0) ? inBevel : -inBevel;
	for (Int16 index = 1; index <= theBevel; index++)
		{
		if (inSides.top)
			{
			::MoveTo(theBevelRect.right, theBevelRect.top);
			::LineTo(theBevelRect.left, theBevelRect.top);
			}
		if (inSides.left)
			{
			// 1997-03-24 pkc
			// Don't draw topleft corner twice
			if (inSides.top)
				::MoveTo(theBevelRect.left, theBevelRect.top + 1);
			else
				::MoveTo(theBevelRect.left, theBevelRect.top);
			::LineTo(theBevelRect.left, theBevelRect.bottom);
			}
		if (inSides.top)
			theBevelRect.top++;
		if (inSides.left)
			theBevelRect.left++;
		if (inSides.bottom)
			theBevelRect.bottom--;
		if (inSides.right)
			theBevelRect.right--;
		}
		
	theBevelRect = inRect;
	theBevelRect.bottom--;
	theBevelRect.right--;

	if (inBevel >= 0)
		{
		::RGBForeColor(&theSubColor);
		::OpColor(&sDarker);
		::PenMode(subPin);
		}
	else
		{
		::RGBForeColor(&theAddColor);
		::OpColor(&sLighter);
		::PenMode(addPin);
		}

	theBevel = (inBevel >= 0) ? inBevel : -inBevel;
	for (Int16 index = 1; index <= theBevel; index++)
		{
		if (inSides.bottom)
			{
			::MoveTo(theBevelRect.left, theBevelRect.bottom);
			::LineTo(theBevelRect.right, theBevelRect.bottom);
			}
		if (inSides.right)
			{
			// 1997-03-24 pkc
			// Don't draw bottomright corner twice
			if (inSides.bottom)
				::MoveTo(theBevelRect.right, theBevelRect.bottom - 1);
			else
				::MoveTo(theBevelRect.right, theBevelRect.bottom);
			::LineTo(theBevelRect.right, theBevelRect.top);
			}
		if (inSides.top)
			theBevelRect.top++;
		if (inSides.left)
			theBevelRect.left++;
		if (inSides.bottom)
			theBevelRect.bottom--;
		if (inSides.right)
			theBevelRect.right--;
		}
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	BevelTintRect
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::BevelTintRect(
	const Rect &	inRect,
	Int16 			inBevel,
	Uint16			inTopTint,
	Uint16			inBottomTint)
{
	SBooleanRect sides = { true, true, true, true };
	BevelTintPartialRect(inRect, inBevel, inTopTint, inBottomTint, sides);
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	BevelTintRoundRect
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::BevelTintRoundRect(
	const Rect&		inRect,
	Int16			inOvalWidth,
	Int16			inOvalHeight,
	Uint16			inTint,
	Boolean			inLighten)
{
	StColorPenState thePenSaver;
	thePenSaver.Normalize();
	
	Rect rect = inRect;
	
	RGBColor theTintColor = { inTint, inTint, inTint };

	::RGBForeColor(&theTintColor);

	if (inLighten)
		{
		::OpColor(&sLighter);
		::PenMode(addPin);
		}
	else
		{
		::OpColor(&sDarker);
		::PenMode(subPin);
		}
	
	::FrameRoundRect(&rect, inOvalWidth, inOvalHeight);
}


// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	BevelTintLine
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::BevelTintLine(
	Int16			inStartX,
	Int16			inStartY,
	Int16			inEndX,
	Int16			inEndY,
	Uint16			inTint,
	Boolean			inLighten)
{
	StColorPenState thePenSaver;
	thePenSaver.Normalize();

	RGBColor theTintColor = { inTint, inTint, inTint };
	
	::RGBForeColor(&theTintColor);

	if (inLighten)
		{
		::OpColor(&sLighter);
		::PenMode(addPin);
		}
	else
		{
		::OpColor(&sDarker);
		::PenMode(subPin);
		}
	
	::MoveTo(inStartX, inStartY);
	::LineTo(inEndX, inEndY);
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	BevelTintPixel
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
void UGraphicGizmos::BevelTintPixel(
	Int16			inX,
	Int16			inY,
	Uint16			inTint,
	Boolean			inLighten)
{
	BevelTintLine(inX, inY, inX, inY, inTint, inLighten);
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	RaiseColorVolume
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::RaiseColorVolume(
	const Rect&		inRect,
	Uint16			inTint)
{
	StColorPenState		theSavedState;
	theSavedState.Normalize();

	RGBColor theAddColor = { inTint, inTint, inTint };
	::RGBForeColor(&theAddColor);
	::OpColor(&sLighter);
	::PenMode(addPin);
	::PaintRect(&inRect);
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	LowerColorVolume
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::LowerColorVolume(
	const Rect&		inRect,
	Uint16			inTint)
{
	StColorPenState		theSavedState;
	theSavedState.Normalize();

	RGBColor theSubColor = { inTint, inTint, inTint };
	::RGBForeColor(&theSubColor);
	::OpColor(&sDarker);
	::PenMode(subPin);
	::PaintRect(&inRect);
}


// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	LowerRoundRectColorVolume
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::LowerRoundRectColorVolume(
	const Rect&		inRect,
	Int16			inOvalWidth,
	Int16			inOvalHeight,
	Uint16			inTint)
{
	StColorPenState		theSavedState;
	theSavedState.Normalize();

	RGBColor theSubColor = { inTint, inTint, inTint };
	::RGBForeColor(&theSubColor);
	::OpColor(&sDarker);
	::PenMode(subPin);
	::PaintRoundRect(&inRect, inOvalWidth, inOvalHeight);
}


// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	PaintDisabledRect
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::PaintDisabledRect(
	const Rect&		inRect,
	Uint16			inTint,
	Boolean			inMakeLighter)
{
	StColorPenState		theSavedState;
	theSavedState.Normalize();
	
	RGBColor theOpColor;
	theOpColor.red = theOpColor.blue = theOpColor.green = inTint;
	
	RGBColor theNewColor;
	if (inMakeLighter) 
		theNewColor.red = theNewColor.blue = theNewColor.green = 0xFFFF;
	else 
		theNewColor.red = theNewColor.blue = theNewColor.green = 0x0000;
	
	::OpColor(&theOpColor);
	::RGBForeColor(&theNewColor);
	::PenMode(blend);
	::PenPat(&qd.black);
	::PaintRect(&inRect);
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	CenterRectOnRect
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::CenterRectOnRect(
	Rect			&inRect,
	const Rect		&inOnRect)
{
	Int16 theRectHeight = RectHeight(inRect);
	Int16 theRectWidth = RectWidth(inRect);
				
	inRect.top = inOnRect.top + ((RectHeight(inOnRect) - theRectHeight) / 2);
	inRect.bottom = inRect.top + theRectHeight;
	inRect.left = inOnRect.left + ((RectWidth(inOnRect) - theRectWidth) / 2);
	inRect.right = inRect.left + theRectWidth;
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	AlignRectOnRect
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::AlignRectOnRect(
	Rect&			inRect,
	const Rect&		inOnRect,
	Uint16			inAlignment)
{
	Int16 theRectHeight = RectHeight(inRect);
	Int16 theRectWidth = RectWidth(inRect);

	switch (inAlignment)
		{
		case kAlignVerticalCenter:
			inRect.top = inOnRect.top + ((RectHeight(inOnRect) - theRectHeight) / 2);
			inRect.bottom = inRect.top + theRectHeight;
			break;
			
		case kAlignTop:
			inRect.top = inOnRect.top;
			inRect.bottom = inRect.top + theRectHeight;
			break;
			
		case kAlignBottom:
			inRect.bottom = inOnRect.bottom;
			inRect.top = inRect.bottom - theRectHeight;
			break;
			
		case kAlignHorizontalCenter:
			inRect.left = inOnRect.left + ((RectWidth(inOnRect) - theRectWidth) / 2);
			inRect.right = inRect.left + theRectWidth;
			break;
			
		case kAlignAbsoluteCenter:
			UGraphicGizmos::CenterRectOnRect(inRect, inOnRect);
			break;
			
		case kAlignCenterTop:
			inRect.left = inOnRect.left + ((RectWidth(inOnRect) - theRectWidth) / 2);
			inRect.right = inRect.left + theRectWidth;
			inRect.top = inOnRect.top;
			inRect.bottom = inRect.top + theRectHeight;
			break;
			
		case kAlignCenterBottom:
			inRect.left = inOnRect.left + ((RectWidth(inOnRect) - theRectWidth) / 2);
			inRect.right = inRect.left + theRectWidth;
			inRect.bottom = inOnRect.bottom;
			inRect.top = inRect.bottom - theRectHeight;
			break;
			
		case kAlignLeft:
			inRect.left = inOnRect.left;
			inRect.right = inRect.left + theRectWidth;
			break;
			
		case kAlignCenterLeft:
			inRect.top = inOnRect.top + ((RectHeight(inOnRect) - theRectHeight) / 2);
			inRect.bottom = inRect.top + theRectHeight;
			inRect.left = inOnRect.left;
			inRect.right = inRect.left + theRectWidth;
			break;
			
		case kAlignTopLeft:
			inRect.top = inOnRect.top;
			inRect.bottom = inRect.top + theRectHeight;
			inRect.left = inOnRect.left;
			inRect.right = inRect.left + theRectWidth;
			break;
			
		case kAlignBottomLeft:
			inRect.bottom = inOnRect.bottom;
			inRect.top = inRect.bottom - theRectHeight;
			inRect.left = inOnRect.left;
			inRect.right = inRect.left + theRectWidth;
			break;
			
		case kAlignRight:
			inRect.right = inOnRect.right;
			inRect.left = inRect.right - theRectWidth;
			break;
			
		case kAlignCenterRight:
			inRect.top = inOnRect.top + ((RectHeight(inOnRect) - theRectHeight) / 2);
			inRect.bottom = inRect.top + theRectHeight;
			inRect.right = inOnRect.right;
			inRect.left = inRect.right - theRectWidth;
			break;
			
		case kAlignTopRight:
			inRect.top = inOnRect.top;
			inRect.bottom = inRect.top + theRectHeight;
			inRect.right = inOnRect.right;
			inRect.left = inRect.right - theRectWidth;
			break;
			
		case kAlignBottomRight:
			inRect.bottom = inOnRect.bottom;
			inRect.top = inRect.bottom - theRectHeight;
			inRect.right = inOnRect.right;
			inRect.left = inRect.right - theRectWidth;
			break;
			
		default:
			Assert_(false);		// invalid selector
			break;
		}
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	PadAlignedRect
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::PadAlignedRect(
	Rect&			ioRect,
	Uint16			inPad,
	Uint16			inAlignment)
{
	Int16 theHOffset = 0, theVOffset = 0;

	switch (inAlignment)
		{
		case kAlignTop:
		case kAlignCenterTop:
			theVOffset = inPad;
			break;
			
		case kAlignBottom:
		case kAlignCenterBottom:
			theVOffset = -inPad;
			break;
						
		case kAlignLeft:
		case kAlignCenterLeft:
			theHOffset = inPad;
			break;
			
		case kAlignTopLeft:
			theVOffset = inPad;
			theHOffset = inPad;
			break;
						
		case kAlignBottomLeft:
			theVOffset = -inPad;
			theHOffset = inPad;
			break;
			
		case kAlignRight:
		case kAlignCenterRight:
			theHOffset = -inPad;
			break;
						
		case kAlignTopRight:
			theVOffset = inPad;
			theHOffset = -inPad;
			break;
			
		case kAlignBottomRight:
			theVOffset = -inPad;
			theHOffset = -inPad;
			break;
			
		
		case kAlignAbsoluteCenter:
			// this is to prevent the Assert_
			break;
		
		default:
			Assert_(false);		// invalid selector
			break;
		}
	
	if (theHOffset != 0)
		{
		Int16 theRectWidth = RectWidth(ioRect);
		ioRect.left += theHOffset;
		ioRect.right = ioRect.left + theRectWidth;
		}
		
	if (theVOffset != 0)
		{
		Int16 theRectHeight = RectHeight(ioRect);
		ioRect.top += theVOffset;
		ioRect.bottom = ioRect.top + theRectHeight;
		}
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	CenterStringInRect
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::CenterStringInRect(
	const StringPtr inString,
	const Rect		&inRect)
{
	FontInfo theFontInfo;
	::GetFontInfo(&theFontInfo);
		
	Point thePoint;
	thePoint.h = inRect.left + ((RectWidth(inRect) - StringWidth(inString)) / 2);
		
	Int16 theFontHeight = theFontInfo.ascent + theFontInfo.descent + 1;
	thePoint.v = inRect.top + ((RectHeight(inRect) - theFontHeight) / 2) + theFontInfo.ascent;
	
	MoveTo(thePoint.h, thePoint.v);
	::DrawString(inString);
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	PlaceStringInRect
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::PlaceStringInRect(
	const StringPtr inString,
	const Rect 		&inRect,
	Int16			inHorizJustType,
	Int16			inVertJustType,
	const FontInfo*	inFontInfo)
{
	Point  thePoint;

	thePoint = CalcStringPosition(inRect, ::StringWidth(inString), inHorizJustType, inVertJustType, inFontInfo);
	::MoveTo(thePoint.h, thePoint.v);
	::DrawString(inString);
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	PlaceTextInRect
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::PlaceTextInRect(
	const char* 	inText,
	Uint32			inTextLength,
	const Rect 		&inRect,
	Int16			inHorizJustType,
	Int16			inVertJustType,
	const FontInfo*	inFontInfo,
	Boolean			inDoTruncate,
	TruncCode		inTruncWhere)
{
	if (inRect.right <= inRect.left)
		return;
	const char* text = inText;
	short length = inTextLength;
	char buf[256];
	if (inDoTruncate)
	{
		// TSM - Text is not necessarily null terminated!
		::strncpy(buf, inText, sizeof(buf) < inTextLength ? sizeof(buf) : inTextLength);
		
		// BUG IN APPLE's ::TruncText workaround is to call our own version
		// that has the added bonus of not crashing when you try and trunc
		// in the middle. Crash in Apple's code happens when you have a small space
		// and you degenerate into choosing between truncating in the beginning or end.
		
		short available = inRect.right - inRect.left;
		if (inTruncWhere == truncMiddle)
			MiddleTruncationThatWorks(buf, length, available);
		else
			::TruncText(available, buf, &length, inTruncWhere);
			
		text = buf;
	}
	Point thePoint = CalcStringPosition(
		 	inRect,
		 	::TextWidth(text, 0, length),
		 	inHorizJustType,
		 	inVertJustType,
		 	inFontInfo);
	::MoveTo(thePoint.h, thePoint.v);
	::DrawText(text, 0, length);
}	



// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	CalcStringPosition
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

Point UGraphicGizmos::CalcStringPosition(
	const Rect		&inRect,
	Int16			inStringWidth,
	Int16			inHorizJustType,
	Int16			inVertJustType,
	const FontInfo	*inFontInfo)
{
	Point  thePoint;
	FontInfo 			theFontInfo;
	const FontInfo*	theFontInfoPtr;
	
	theFontInfoPtr = inFontInfo;
	if (inFontInfo == NULL)
		{
		::GetFontInfo(&theFontInfo);
		theFontInfoPtr = &theFontInfo;
		}

	Int16 theFontHeight = theFontInfoPtr->ascent + theFontInfoPtr->descent; // + theFontInfoPtr->leading;
	Int16 theRectHeight = RectHeight(inRect);
	if (inHorizJustType == teFlushDefault)
		{
		inHorizJustType = ::GetSysDirection();
		if (inHorizJustType == teFlushDefault) // that's the way it behaves:
			inHorizJustType = teFlushLeft;
		}
	switch (inHorizJustType)
		{
		case teFlushRight:
			thePoint.h = inRect.right - inStringWidth;
			break;
			
		case teFlushLeft:
			thePoint.h = inRect.left;
			break;
				
		case teCenter:
		default:
			thePoint.h = inRect.left + ((RectWidth(inRect) - inStringWidth) / 2);
			break;
		}
		
	switch (inVertJustType)
		{
		case teFlushTop:
			thePoint.v = inRect.top + theFontInfoPtr->ascent;
			break;
			
		case teFlushBottom:
			thePoint.v = inRect.bottom - theFontInfoPtr->descent;
			break;
			
		case teCenter:
		default:
			if (theFontHeight >= theRectHeight)
			{
				// This is a fudge to fix a special case which is, however, common.  The height
				// we calculated above allows extra space at the top for diacriticals.  So if there's
				// a danger that we'll overlap at the bottom, make it overlap at the top, instead.
				thePoint.v = inRect.bottom - theFontInfoPtr->descent;
			}
			else
				thePoint.v
					= inRect.top + ((theRectHeight - theFontHeight) / 2)
					+ theFontInfoPtr->ascent;
			break;
		}
		
	return thePoint;
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	CalcWindowTingeColors
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::CalcWindowTingeColors(WindowPtr inWindowPtr, RGBColor &outLightTinge, RGBColor &outDarkTinge)
{
	AuxWinHandle	theAuxHandle;						// the default AuxWindow data
	Boolean			gotColors;

	::GetAuxWin(inWindowPtr, &theAuxHandle);

	// look for tinge colors in the color table belonging to the given window
	if (!theAuxHandle || !(**theAuxHandle).awCTable ||
		!GetTingeColorsFromColorTable ((**theAuxHandle).awCTable, outLightTinge, outDarkTinge))
		{
		// didn't find them? try the system color table
		// (note: explicit documentation on the wisdom of passing a 0 to GetAuxWin is
		// hard to find; I finally found it in Toolbox Technote 33 (March 1997))
		// (also note: the asserts in here are just what they mean; none of this should
		// ever, ever fail under system 7.)
		::GetAuxWin (0, &theAuxHandle);
		Assert_ (theAuxHandle && (**theAuxHandle).awCTable);
		gotColors = GetTingeColorsFromColorTable ((**theAuxHandle).awCTable, outLightTinge, outDarkTinge);
		Assert_ (gotColors);
		}
}


// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	GetTingeColorsFromColorTable
//		returns true if it finds both tinges in the table
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

Boolean UGraphicGizmos::GetTingeColorsFromColorTable (
		CTabHandle		inColorTable,
		RGBColor		&outLightTinge,
		RGBColor		&outDarkTinge)
{
	Boolean	foundThem;

	foundThem = false;

	// do we have a system 7 sized window color table?
	if ((**inColorTable).ctSize > wTitleBarColor)
		{
		// yes, now search for the tinge color, start at the end
		// because our tinge colors are usually last in the list.
		Boolean bLightFound = false;
		Boolean	bDarkFound = false;
		for (Int16 theIndex = (**inColorTable).ctSize; theIndex > 0; theIndex--)
			{
			if ((**inColorTable).ctTable[theIndex].value == wTingeLight)
				{
				outLightTinge = (**inColorTable).ctTable[theIndex].rgb;
				bLightFound = true;
				}
			else if ((**inColorTable).ctTable[theIndex].value == wTingeDark)
				{
				outDarkTinge = (**inColorTable).ctTable[theIndex].rgb;
				bDarkFound = true;
				}

			foundThem = bLightFound && bDarkFound;
			if (foundThem)
				break;	
			}
		}

	return foundThem;
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	FindInColorTable
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

RGBColor UGraphicGizmos::FindInColorTable(CTabHandle inColorTable, Int16 inColorID)
{
	RGBColor theFoundColor = { 0, 0, 0 };
	
	for (Int16 theIndex = (**inColorTable).ctSize; theIndex > 0; theIndex--)
		{
		if ((**inColorTable).ctTable[theIndex].value == inColorID)
			{
			theFoundColor = (**inColorTable).ctTable[theIndex].rgb;	
			break;
			}
		}
	
	return theFoundColor;
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	MixColor
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

RGBColor UGraphicGizmos::MixColor(
	const RGBColor& inLightColor,
	const RGBColor&	inDarkColor,
	Int16 inShade)
{
	RGBColor theMixedColor;
	
	inShade = 0x0F - inShade;
		// This is necessary because we give shades between light and
		// dark (0% is light), but for colors, $0000 is black and $FFFF 
		// is dark.

	theMixedColor.red	= (Int32) (inLightColor.red   - inDarkColor.red)   * inShade / 15 + inDarkColor.red;
	theMixedColor.green = (Int32) (inLightColor.green - inDarkColor.green) * inShade / 15 + inDarkColor.green;
	theMixedColor.blue  = (Int32) (inLightColor.blue  - inDarkColor.blue)  * inShade / 15 + inDarkColor.blue;

	return theMixedColor;
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	DrawArithPattern
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

void UGraphicGizmos::DrawArithPattern(
	const Rect& 		inFrame,
	const Pattern&		inPattern,
	Uint16				inTint,
	Boolean				inLighten)
{
	StColorPenState thePenSaver;
	thePenSaver.Normalize();

	RGBColor thePinColor = { inTint, inTint, inTint };

	::RGBBackColor(&sDarker);
	::RGBForeColor(&thePinColor);

	if (inLighten)
		{
		::OpColor(&sLighter);
		::PenMode(addPin);
		}
	else
		{
		::OpColor(&sDarker);
		::PenMode(subPin);
		}

	::PenPat(&inPattern);
	::PaintRect(&inFrame);
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	DrawPopupArrow
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	This function is based in part on LGAPopup::DrawPopupArrow().

void
UGraphicGizmos::DrawPopupArrow(
	const Rect&			inLocalFrame,
	Boolean				inIsEnabled,
	Boolean				inIsActive,
	Boolean				inIsHilited)
{
	Rect	theFrame = inLocalFrame;
	Int16	thePopupArrowHeight	= (theFrame.bottom - theFrame.top + 1);
	
	// ₯ Setup a device loop so that we can handle drawing at the correct bit depth
	
	// this is a hack to avoid a clipping problem--LineTo draws down and to the right of the coordinates
	// we'll add a pixel to the right and then decrement it after StDeviceLoop call which clips
	++theFrame.right;
	++theFrame.bottom;
	
	StDeviceLoop	theLoop ( theFrame );

	--theFrame.right;
	--theFrame.bottom;

	Int16			depth;
	while ( theLoop.NextDepth ( depth )) 
	{
		if ( depth < 4 )
		{
			// ₯ If we are hilited and enabled and active we draw the arrow
			//   in white otherwise it is drawn in black
			::RGBForeColor ( &(inIsHilited && inIsEnabled && inIsActive ?
												UGAColorRamp::GetWhiteColor () :
												UGAColorRamp::GetBlackColor()));
			
			// ₯ If we are disabled we draw in gray
			if ( !inIsEnabled)
				::PenPat ( &UQDGlobals::GetQDGlobals()->gray );
		}
		else
		{
			StColorPenState::Normalize ();
			
			// ₯ Handle the actual drawing of the arrow,it is drawn in black in its normal
			// state, when it is hilited it is drawn in white, and it is drawn in gray when
			// dimmed
			if ( inIsHilited && inIsActive )
				::RGBForeColor ( &(inIsEnabled ? UGAColorRamp::GetWhiteColor() :
												UGAColorRamp::GetColor(7)) );
			else if ( !inIsEnabled || !inIsActive)
				::RGBForeColor ( &UGAColorRamp::GetColor(7));
			else
				::RGBForeColor ( &UGAColorRamp::GetBlackColor());
		}

		// ₯ Arrow drawing loop draws thePopupArrowHeight rows to make the arrow
		Int16  counter;
		for ( counter = 0; counter <= thePopupArrowHeight - 1; counter++ )
		{
			::MoveTo ( theFrame.left + counter, theFrame.top + counter );
			::LineTo ( theFrame.right - counter, theFrame.top + counter );
		}
	}
}	

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	Class CSicn
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

CSicn::CSicn()
{
	::SetRect(&mSicnRect, 0, 0, 16, 16);
}

CSicn::CSicn(ResIDT inSicnID, Int16 inIndex)
{
	::SetRect(&mSicnRect, 0, 0, 16, 16);
	LoadSicnData(inSicnID, inIndex);
}

void CSicn::LoadSicnData(ResIDT inSicnID, Int16 inIndex)
{
	StResource theSicnList('SICN', inSicnID);
	ThrowIf_((::GetHandleSize(theSicnList.mResourceH) / sizeof(SicnT)) <= inIndex);

	StHandleLocker theLocker(theSicnList);
	::BlockMoveData((Ptr)(*((SicnT *)(*theSicnList.mResourceH) + inIndex)), mSicnData, sizeof(SicnT));
}

void CSicn::Plot(Int16 inMode)
{
	CopyImage(mSicnRect, inMode);
}

void CSicn::Plot(const Rect &inRect, Int16 inMode)
{
	CopyImage(inRect, inMode);
}

void CSicn::CopyImage(const Rect &inRect, Int16 inMode)
{
	// Set up a BitMap for the sicn
	BitMap theSourceBits;
	theSourceBits.baseAddr = (Ptr)(mSicnData);
	theSourceBits.rowBytes = 2;
	::SetRect(&theSourceBits.bounds, 0, 0, 16, 16);

	// draw the small icon in the current grafport
	::CopyBits(&theSourceBits, &(UQDGlobals::GetCurrentPort()->portBits),
				 &theSourceBits.bounds, &inRect, inMode, nil);
}

// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯	Class CIconFamily
// ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

CIconFamily::CIconFamily(ResIDT inFamilyID)
{
	mFamilyID = inFamilyID;
	mIconRect.top = 0;
	mIconRect.left = 0;
	mIconRect.bottom = 0;
	mIconRect.right = 0;
}

CIconFamily::~CIconFamily()
{
}

void CIconFamily::Plot(
	IconAlignmentType inAlign,
	IconTransformType inTransform)
{
	::PlotIconID(&mIconRect, inAlign, inTransform, mFamilyID);
}

void CIconFamily::Plot(
	const Rect& 		inRect,
	IconAlignmentType 	inAlign,
	IconTransformType 	inTransform)
{
	::PlotIconID(&inRect, inAlign, inTransform, mFamilyID);
}

CIconFamily::CIconFamily()
{
	Assert_(false);
}

void CIconFamily::CalcBestSize(const Rect& inContainer)
{
	mIconRect.top = mIconRect.left = 0;

	if ((RectWidth(inContainer) >= 32) && (RectHeight(inContainer) >= 32))
		mIconRect.right = mIconRect.bottom = 32;
	else if ((RectWidth(inContainer) >= 16) && (RectHeight(inContainer) >= 16))
		mIconRect.right = mIconRect.bottom = 16;
	else if ((RectWidth(inContainer) >= 16) && (RectHeight(inContainer) >= 12))
		{
		mIconRect.right = 16;
		mIconRect.bottom = 12;
		}
	else
		Assert_(false);	// you really wont be able to draw in bounds
}
