#include "shellprv.h"
#pragma  hdrstop

int IntSqrt(unsigned long dwNum)
{
	// We will keep shifting dwNum left and look at the top two bits.

	// initialize sqrt and remainder to 0.
	DWORD dwSqrt = 0, dwRemain = 0, dwTry;
	int i;

	// We iterate 16 times, once for each pair of bits.
	for (i=0; i<16; ++i)
	{
		// Mask off the top two bits of dwNum and rotate them into the
		// bottom of the remainder
		dwRemain = (dwRemain<<2) | (dwNum>>30);

		// Now we shift the sqrt left; next we'll determine whether the
		// new bit is a 1 or a 0.
		dwSqrt <<= 1;

		// This is where we double what we already have, and try a 1 in
		// the lowest bit.
		dwTry = dwSqrt*2 + 1;

		if (dwRemain >= dwTry)
		{
			// The remainder was big enough, so subtract dwTry from
			// the remainder and tack a 1 onto the sqrt.
			dwRemain -= dwTry;
			dwSqrt |= 0x01;
		}

		// Shift dwNum to the left by 2 so we can work on the next few
		// bits.
		dwNum <<= 2;
	}

	return(dwSqrt);
}

STDAPI_(VOID) DrawPie(HDC hDC, LPCRECT lprcItem, UINT uPctX10, BOOL TrueZr100,
                  UINT uOffset, const COLORREF *lpColors)
{
	int cx, cy, rx, ry, x, y;
	int uQPctX10;
	RECT rcItem;
	HRGN hEllRect, hEllipticRgn, hRectRgn;
	HBRUSH hBrush, hOldBrush;
	HPEN hPen, hOldPen;
    DWORD dwOldLayout;

	rcItem = *lprcItem;
	rcItem.left = lprcItem->left;
	rcItem.top = lprcItem->top;
	rcItem.right = lprcItem->right - rcItem.left;
	rcItem.bottom = lprcItem->bottom - rcItem.top - uOffset;

	rx = rcItem.right / 2;
	cx = rcItem.left + rx - 1;
	ry = rcItem.bottom / 2;
	cy = rcItem.top + ry - 1;
	if (rx<=10 || ry<=10)
	{
		return;
	}

    dwOldLayout = SET_DC_LAYOUT(hDC, 0);

	rcItem.right = rcItem.left+2*rx;
	rcItem.bottom = rcItem.top+2*ry;

	if (uPctX10 > 1000)
	{
		uPctX10 = 1000;
	}

	/* Translate to first quadrant of a Cartesian system
	*/
	uQPctX10 = (uPctX10 % 500) - 250;
	if (uQPctX10 < 0)
	{
		uQPctX10 = -uQPctX10;
	}

	/* Calc x and y.  I am trying to make the area be the right percentage.
	** I don't know how to calculate the area of a pie slice exactly, so I
	** approximate it by using the triangle area instead.
	*/
	if (uQPctX10 < 120)
	{
		x = IntSqrt(((DWORD)rx*(DWORD)rx*(DWORD)uQPctX10*(DWORD)uQPctX10)
			/((DWORD)uQPctX10*(DWORD)uQPctX10+(250L-(DWORD)uQPctX10)*(250L-(DWORD)uQPctX10)));

		y = IntSqrt(((DWORD)rx*(DWORD)rx-(DWORD)x*(DWORD)x)*(DWORD)ry*(DWORD)ry/((DWORD)rx*(DWORD)rx));
	}
	else
	{
		y = IntSqrt((DWORD)ry*(DWORD)ry*(250L-(DWORD)uQPctX10)*(250L-(DWORD)uQPctX10)
			/((DWORD)uQPctX10*(DWORD)uQPctX10+(250L-(DWORD)uQPctX10)*(250L-(DWORD)uQPctX10)));

		x = IntSqrt(((DWORD)ry*(DWORD)ry-(DWORD)y*(DWORD)y)*(DWORD)rx*(DWORD)rx/((DWORD)ry*(DWORD)ry));
	}

	/* Switch on the actual quadrant
	*/
	switch (uPctX10 / 250)
	{
	case 1:
		y = -y;
		break;

	case 2:
		break;

	case 3:
		x = -x;
		break;

	default: // case 0 and case 4
		x = -x;
		y = -y;
		break;
	}

	/* Now adjust for the center.
	*/
	x += cx;
	y += cy;

        // Hack to get around bug in NTGDI

        x = x < 0 ? 0 : x;

	/* Draw the shadows using regions (to reduce flicker).
	*/
	hEllipticRgn = CreateEllipticRgnIndirect(&rcItem);
	OffsetRgn(hEllipticRgn, 0, uOffset);
	hEllRect = CreateRectRgn(rcItem.left, cy, rcItem.right, cy+uOffset);
	hRectRgn = CreateRectRgn(0, 0, 0, 0);
	CombineRgn(hRectRgn, hEllipticRgn, hEllRect, RGN_OR);
	OffsetRgn(hEllipticRgn, 0, -(int)uOffset);
	CombineRgn(hEllRect, hRectRgn, hEllipticRgn, RGN_DIFF);

	/* Always draw the whole area in the free shadow/
	*/
	hBrush = CreateSolidBrush(lpColors[DP_FREESHADOW]);
	if (hBrush)
	{
		FillRgn(hDC, hEllRect, hBrush);
		DeleteObject(hBrush);
	}

	/* Draw the used shadow only if the disk is at least half used.
	*/
	if (uPctX10>500 && (hBrush=CreateSolidBrush(lpColors[DP_USEDSHADOW]))!=NULL)
	{
		DeleteObject(hRectRgn);
		hRectRgn = CreateRectRgn(x, cy, rcItem.right, lprcItem->bottom);
		CombineRgn(hEllipticRgn, hEllRect, hRectRgn, RGN_AND);
		FillRgn(hDC, hEllipticRgn, hBrush);
		DeleteObject(hBrush);
	}

	DeleteObject(hRectRgn);
	DeleteObject(hEllipticRgn);
	DeleteObject(hEllRect);

	hPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME));
	hOldPen = SelectObject(hDC, hPen);

	if((uPctX10 < 100) && (cy == y))
	{
	    hBrush = CreateSolidBrush(lpColors[DP_FREECOLOR]);
	    hOldBrush = SelectObject(hDC, hBrush);
	    if((TrueZr100 == FALSE) || (uPctX10 != 0))
	    {
		Pie(hDC, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom,
			rcItem.left, cy, x, y);
	    }
	    else
	    {
		Ellipse(hDC, rcItem.left, rcItem.top, rcItem.right,
			     rcItem.bottom);
	    }
	}
	else if((uPctX10 > (1000 - 100)) && (cy == y))
	{
	    hBrush = CreateSolidBrush(lpColors[DP_USEDCOLOR]);
	    hOldBrush = SelectObject(hDC, hBrush);
	    if((TrueZr100 == FALSE) || (uPctX10 != 1000))
	    {
		Pie(hDC, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom,
			rcItem.left, cy, x, y);
	    }
	    else
	    {
		Ellipse(hDC, rcItem.left, rcItem.top, rcItem.right,
			     rcItem.bottom);
	    }
	}
	else
	{
	    hBrush = CreateSolidBrush(lpColors[DP_USEDCOLOR]);
	    hOldBrush = SelectObject(hDC, hBrush);

	    Ellipse(hDC, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
	    SelectObject(hDC, hOldBrush);
	    DeleteObject(hBrush);

	    hBrush = CreateSolidBrush(lpColors[DP_FREECOLOR]);
	    hOldBrush = SelectObject(hDC, hBrush);
	    Pie(hDC, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom,
		    rcItem.left, cy, x, y);
	}
	SelectObject(hDC, hOldBrush);
	DeleteObject(hBrush);

	/* Do not draw the lines if the %age is truely 0 or 100 (completely
	** empty disk or completly full disk)
	*/
	if((TrueZr100 == FALSE) || ((uPctX10 != 0) && (uPctX10 != 1000)))
	{
	    Arc(hDC, rcItem.left, rcItem.top+uOffset, rcItem.right, rcItem.bottom+uOffset,
		    rcItem.left, cy+uOffset, rcItem.right, cy+uOffset-1);
	    MoveToEx(hDC, rcItem.left, cy, NULL);
	    LineTo(hDC, rcItem.left, cy+uOffset);
	    MoveToEx(hDC, rcItem.right-1, cy, NULL);
	    LineTo(hDC, rcItem.right-1, cy+uOffset);

	    if (uPctX10 > 500)
	    {
		    MoveToEx(hDC, x, y, NULL);
		    LineTo(hDC, x, y+uOffset);
	    }
	}
	SelectObject(hDC, hOldPen);
	DeleteObject(hPen);
    SET_DC_LAYOUT(hDC, dwOldLayout);
	
}
