BOOL CBCGPTagManager::ParseColor (const CString& strItem, CBCGPColor& value)
{
	CBCGPTagManager tm (strItem);

	CStringArray sa;

	CString strA, strR, strG, strB;

	tm.ExcludeTag (s_A, strA);
	strA.TrimLeft ();
	strA.TrimRight ();
	tm.ExcludeTag (s_R, strR);
	strR.TrimLeft ();
	strR.TrimRight ();
	tm.ExcludeTag (s_G, strG);
	strG.TrimLeft ();
	strG.TrimRight ();
	tm.ExcludeTag (s_B, strB);
	strB.TrimLeft ();
	strB.TrimRight ();

	if (strR.IsEmpty () || strG.IsEmpty () || strB.IsEmpty ())
	{
		if (!ParseString (strItem, _T(","), sa, TRUE, FALSE))
		{
			strR = tm.GetBuffer ();
			strR.TrimLeft ();
			strR.TrimRight ();

			sa.Add (strR);
		}
	}
	else
	{
		sa.Add (strR);
		sa.Add (strG);
		sa.Add (strB);

		if (!strA.IsEmpty ())
		{
			sa.Add (strA);
		}
	}

	if (sa.GetSize () > 0)
	{
		const int count = (int) sa.GetSize ();
		if (count >= 3)
		{
			value.r = bcg_clamp((double)_ttol(sa[0]) / 255.0, 0.0, 1.0);
			value.g = bcg_clamp((double)_ttol(sa[1]) / 255.0, 0.0, 1.0);
			value.b = bcg_clamp((double)_ttol(sa[2]) / 255.0, 0.0, 1.0);
			value.a = count == 4 ? bcg_clamp((double)_ttol(sa[3]) / 255.0, 0.0, 1.0) : 1.0;

			return TRUE;
		}
	}

	return FALSE;
}
BOOL CBCGPTagManager::ParseTextFormat (const CString& strItem, CBCGPTextFormat& value)
{
	CBCGPTagManager tm (strItem);

	CString family;
	tm.ReadString (s_TextFormatFamily, family);
	if (family.IsEmpty ())
	{
		return FALSE;
	}

	double size = 0.0;
	tm.ReadDouble (s_TextFormatSize, size);
	if (size == 0.0)
	{
		return FALSE;
	}

	int nValue = 0;
	tm.ReadInt (s_TextFormatWeight, nValue);
	long weight = (long)bcg_clamp(nValue, FW_THIN, FW_HEAVY);

	nValue = (int)CBCGPTextFormat::BCGP_FONT_STYLE_NORMAL;
	tm.ReadInt (s_TextFormatStyle, nValue);
	CBCGPTextFormat::BCGP_FONT_STYLE style = (CBCGPTextFormat::BCGP_FONT_STYLE)
		bcg_clamp(nValue, (int)CBCGPTextFormat::BCGP_FONT_STYLE_NORMAL, (int)CBCGPTextFormat::BCGP_FONT_STYLE_ITALIC);

	CString locale;
	tm.ReadString (s_TextFormatLocale, locale);

	CBCGPTextFormat format(family, (float)size, weight, style, locale);

	nValue = (int)CBCGPTextFormat::BCGP_TEXT_ALIGNMENT_LEADING;
	tm.ReadInt (s_TextFormatAlignHorz, nValue);
	format.SetTextAlignment ((CBCGPTextFormat::BCGP_TEXT_ALIGNMENT)
		bcg_clamp(nValue, (int)CBCGPTextFormat::BCGP_TEXT_ALIGNMENT_LEADING, (int)CBCGPTextFormat::BCGP_TEXT_ALIGNMENT_CENTER));

	nValue = (int)CBCGPTextFormat::BCGP_TEXT_ALIGNMENT_LEADING;
	tm.ReadInt (s_TextFormatAlignVert, nValue);
	format.SetTextVerticalAlignment ((CBCGPTextFormat::BCGP_TEXT_ALIGNMENT)
		bcg_clamp(nValue, (int)CBCGPTextFormat::BCGP_TEXT_ALIGNMENT_LEADING, (int)CBCGPTextFormat::BCGP_TEXT_ALIGNMENT_CENTER));

	BOOL bValue = FALSE;
	tm.ReadBool (s_TextFormatWordWrap, bValue);
	format.SetWordWrap (bValue);

	bValue = FALSE;
	tm.ReadBool (s_TextFormatClipping, bValue);
	format.SetClipText (bValue);

	double dValue = 0.0;
	tm.ReadDouble (s_TextFormatAngle, dValue);
	format.SetDrawingAngle (dValue);

	value = format;

	return TRUE;
}
Esempio n. 3
0
void bcg_setLineLength (const CBCGPPoint& pt1, CBCGPPoint& pt2, double dNewLength)
{
    double dLen = bcg_distance (pt1, pt2);
    double cosT = (dLen > DBL_EPSILON) ? bcg_clamp ((pt2.x - pt1.x) / dLen, -1.0, 1.0) : 1.0;
    double sinT = (dLen > DBL_EPSILON) ? bcg_clamp ((pt2.y - pt1.y) / dLen, -1.0, 1.0) : 0.0;

    pt2.x = pt1.x + dNewLength * cosT;
    pt2.y = pt1.y + dNewLength * sinT;
}
CString CBCGPTagManager::WriteBrush (const CString& strTag, const CBCGPBrush& value)
{
	CString strValue;

	WriteTag (strValue, WriteInt (s_BrushType, value.GetGradientType(), CBCGPBrush::BCGP_NO_GRADIENT));

	if (value.GetGradientType() == CBCGPBrush::BCGP_NO_GRADIENT)
	{
		WriteTag (strValue, WriteColor (s_BrushColor, value.GetColor()));
	}
	else
	{
		CString strColors;
		WriteTag (strColors, WriteColor (s_BrushColor, value.GetColor()));
		WriteTag (strColors, WriteColor (s_BrushColor, value.GetGradientColor()));
		WriteItem (strValue, s_BrushColors, strColors);
	}

	WriteTag (strValue, WriteInt (s_Opacity, bcg_clamp(bcg_round(value.GetOpacity() * 255.0), 0, 255), 255));

	CString str;
	WriteItem (str, strTag, strValue);

	return str;
}
CBCGPColorTableFunction::CBCGPColorTableFunction(int size)
	: m_Colors(NULL)
{
	m_Size = bcg_clamp (size, 0, 256);
	ASSERT(m_Size > 1);

	m_R.SetInput (0, m_Size - 1, 1);
	m_G.SetInput (0, m_Size - 1, 1);
	m_B.SetInput (0, m_Size - 1, 1);
}
BOOL CBCGPTagManager::ParseBrush (const CString& strItem, CBCGPBrush& value)
{
	CBCGPTagManager tm (strItem);

	int type = CBCGPBrush::BCGP_NO_GRADIENT;
	tm.ReadInt(s_BrushType, type);
	type = bcg_clamp(type, CBCGPBrush::BCGP_NO_GRADIENT, CBCGPBrush::BCGP_GRADIENT_RADIAL_BOTTOM_RIGHT);
	int opacity = 255;
	tm.ReadInt (s_Opacity, opacity);

	if (type == CBCGPBrush::BCGP_NO_GRADIENT)
	{
		CBCGPColor clr;
		tm.ReadColor (s_BrushColor, clr);

		value.SetColor (clr, bcg_clamp((double)opacity / 255.0, 0.0, 1.0));
	}
	else
	{
		CString strColors;

		if (tm.ExcludeTag (s_BrushColors, strColors))
		{
			CBCGPTagManager tmColors(strColors);

			CBCGPColor clr1;
			tmColors.ReadColor (s_BrushColor, clr1);
			CBCGPColor clr2;
			tmColors.ReadColor (s_BrushColor, clr2);

			value.SetColors (clr1, clr2, (CBCGPBrush::BCGP_GRADIENT_TYPE)type, bcg_clamp((double)opacity / 255.0, 0.0, 1.0));
		}
	}

	return TRUE;
}
void CBCGPTransferFunction::Calculate(CArray<double, double>& output) const
{
	output.RemoveAll();

	int size = (int)m_Points.GetSize();
	if (size == 0)
	{
		return;
	}

	int count = (int)fabs((m_InputValueMax - m_InputValueMin) / m_InputValueStep) + 1;
	if (count == 1)
	{
		return;
	}

	output.SetSize(count);

	XPoint pt(m_Points[0]);
	if (m_InputValueMin < pt.m_Point)
	{
		for (int i = 0; i <= GetIndex(pt.m_Point); i++)
		{
			output[i] = pt.m_Value;
		}
	}

	if (size > 1)
	{
		pt = m_Points[size - 1];
	}

	if (pt.m_Point < m_InputValueMax)
	{
		for (int i = GetIndex(pt.m_Point); i < count; i++)
		{
			output[i] = pt.m_Value;
		}
	}

	// linear
	size = (int)m_Points.GetSize ();
	if (size < 2)
	{
		return;
	}

	for(long k = size - 1; k >= 1; k--)
	{
		CArray<double, double> points;

		XPoint pt1(m_Points[k - 1]);
		XPoint pt2(m_Points[k]);

		int index1 = GetIndex(pt1.m_Point);
		int index2 = GetIndex(pt2.m_Point);
		double dY = (pt2.m_Value - pt1.m_Value) / (double)(index2 - index1);
		double value = pt1.m_Value;
		for(int i = index1; i <= index2; i++)
		{
			points.Add(bcg_clamp(value, m_OutputValueMin, m_OutputValueMax));
			value += dY;
		}

		if(points.GetSize() <= 2)
		{
			continue;
		}

		int kInsert = index1;
		for(int kk = 0; kk <= points.GetSize() - 1; kk++)
		{
			output[kInsert++] = points[kk];
		}
	}
}
CString CBCGPTagManager::WriteColor (const CString& strTag, const CBCGPColor& value)
{
	CString strValue;
	COLORREF clr = value;

	if (value.a == 1.0)
	{
		strValue.Format (_T("%d, %d, %d"), GetRValue (clr), GetGValue (clr), GetBValue (clr));
	}
	else
	{
		strValue.Format (_T("%d, %d, %d, %d"), GetRValue (clr), GetGValue (clr), GetBValue (clr), bcg_clamp(bcg_round(value.a * 255.0), 0, 255));
	}

	return WriteString (strTag, strValue);
}
//*******************************************************************************
void CBCGPLinearGaugeImpl::CreatePointerPoints(CBCGPPointsArray& arPoints, int nPointerIndex, BOOL bShadow)
{
	if (m_rect.IsRectEmpty())
	{
		return;
	}

	CBCGPLinearGaugePointer* pData = DYNAMIC_DOWNCAST(CBCGPLinearGaugePointer, m_arData[nPointerIndex]);
	if (pData == NULL)
	{
		ASSERT(FALSE);
		return;
	}

	CBCGPGaugeScaleObject* pScale = GetScale(pData->GetScale());
	if (pScale == NULL)
	{
		ASSERT(FALSE);
		return;
	}

	const double scaleRatio = GetScaleRatioMid();

	double dblValue = pData->m_nAnimTimerID != 0 ? pData->m_dblAnimatedValue : pData->m_dblValue;

	double dblSizeMax = max(pScale->m_dblMajorTickMarkSize, 2. * pScale->m_dblMinorTickMarkSize) * scaleRatio;
	double dblSize = dblSizeMax;
	if (dblSize == 0)
	{
		dblSize = 8. * scaleRatio;
	}

	double dblSizePerc = bcg_clamp(pData->m_dblSize, 0.0, 1.0);
	if (dblSizePerc != 0.0)
	{
		dblSize = max(dblSize * dblSizePerc, 2.0);
	}

	CBCGPPoint point;

	if (!ValueToPoint(dblValue, point, pData->GetScale()))
	{
		return;
	}

	double offset = max(pScale->m_dblMajorTickMarkSize, pScale->m_dblMinorTickMarkSize) * scaleRatio;
	offset = max(offset, m_dblMaxRangeSize);

	double x = point.x;
	double y = point.y;

	if (dblSize < dblSizeMax && pData->GetPosition() != CBCGPLinearGaugePointer::BCGP_GAUGE_POSITION_NEAR)
	{
		double dblSizeDelta = dblSizeMax - dblSize;
		if (pData->GetPosition() == CBCGPLinearGaugePointer::BCGP_GAUGE_POSITION_CENTER)
		{
			dblSizeDelta /= 2.0;
		}

		if (m_bIsVertical)
		{
			x += dblSizeDelta;
		}
		else
		{
			y += dblSizeDelta;
		}
	}

	if (bShadow)
	{
		x += 2. * m_sizeScaleRatio.cx;
		y += 2. * m_sizeScaleRatio.cy;
	}

	const double delta = pData->m_dblWidth == 0 ? dblSize / 2 : (pData->m_dblWidth * scaleRatio) / 2;

	switch (pData->GetStyle())
	{
	case CBCGPLinearGaugePointer::BCGP_GAUGE_NEEDLE_TRIANGLE:
		if (m_bIsVertical)
		{
			arPoints.Add(CBCGPPoint(x, y - delta));
			arPoints.Add(CBCGPPoint(x, y + delta));
			arPoints.Add(CBCGPPoint(x + dblSize, y));
		}
		else
		{
			arPoints.Add(CBCGPPoint(x + delta, y));
			arPoints.Add(CBCGPPoint(x - delta, y));
			arPoints.Add(CBCGPPoint(x, y + dblSize));
		}
		break;

	case CBCGPLinearGaugePointer::BCGP_GAUGE_NEEDLE_TRIANGLE_INV:
		if (m_bIsVertical)
		{
			arPoints.Add(CBCGPPoint(x + dblSize, y - delta));
			arPoints.Add(CBCGPPoint(x + dblSize, y + delta));
			arPoints.Add(CBCGPPoint(x, y));
		}
		else
		{
			arPoints.Add(CBCGPPoint(x + delta, y + dblSize));
			arPoints.Add(CBCGPPoint(x - delta, y + dblSize));
			arPoints.Add(CBCGPPoint(x, y));
		}
		break;

	case CBCGPLinearGaugePointer::BCGP_GAUGE_NEEDLE_RECT:
	case CBCGPLinearGaugePointer::BCGP_GAUGE_NEEDLE_CIRCLE:
		if (m_bIsVertical)
		{
			arPoints.Add(CBCGPPoint(x, y + delta));
			arPoints.Add(CBCGPPoint(x, y - delta));

			arPoints.Add(CBCGPPoint(x + dblSize, y - delta));
			arPoints.Add(CBCGPPoint(x + dblSize, y + delta));
		}
		else
		{
			arPoints.Add(CBCGPPoint(x + delta, y + dblSize));
			arPoints.Add(CBCGPPoint(x - delta, y + dblSize));

			arPoints.Add(CBCGPPoint(x - delta, y));
			arPoints.Add(CBCGPPoint(x + delta, y));
		}
		break;

	case CBCGPLinearGaugePointer::BCGP_GAUGE_NEEDLE_DIAMOND:
		if (m_bIsVertical)
		{
			arPoints.Add(CBCGPPoint(x + .5 * dblSize, y + delta));
			arPoints.Add(CBCGPPoint(x, y));

			arPoints.Add(CBCGPPoint(x + .5 * dblSize, y - delta));
			arPoints.Add(CBCGPPoint(x + dblSize, y));
		}
		else
		{
			arPoints.Add(CBCGPPoint(x, y + dblSize));
			arPoints.Add(CBCGPPoint(x - delta, y + .5 * dblSize));

			arPoints.Add(CBCGPPoint(x, y));
			arPoints.Add(CBCGPPoint(x + delta, y + .5 * dblSize));
		}
	}
}
Esempio n. 10
0
//***********************************************************************************************************
void CBCGPBaseVisualCtrl::OnDrawLayeredPopup()
{
	CRect rect;
	GetClientRect (rect);

	if (rect.Width () == 0 || rect.Height () == 0)
	{
		return;
	}

	CPoint point (0, 0);
	CSize size (rect.Size ());

	LPBYTE pBits = NULL;
	HBITMAP hBitmap = CBCGPDrawManager::CreateBitmap_32 (size, (void**)&pBits);
	if (hBitmap == NULL)
	{
		return;
	}

	CBitmap bitmap;
	bitmap.Attach (hBitmap);

	CClientDC clientDC(this);
	CDC dc;
	dc.CreateCompatibleDC (&clientDC);

	CBitmap* pBitmapOld = (CBitmap*)dc.SelectObject (&bitmap);

	if (m_pGM == NULL)
	{
		CBCGPGraphicsManagerParams params;
		params.bAlphaModePremultiplied = TRUE;

		m_pGM = CBCGPGraphicsManager::CreateInstance(CBCGPGraphicsManager::BCGP_GRAPHICS_MANAGER_DEFAULT, TRUE, &params);
	
		if (m_pGM == NULL)
		{
			return;
		}

		m_pGM->EnableTransparentGradient();
	}

	SetRect(rect);

	m_pGM->BindDC(&dc, rect);

	if (!m_pGM->BeginDraw())
	{
		return;
	}

	OnDraw(m_pGM, rect);

	SetDirty(FALSE);

	m_pGM->EndDraw();

	m_pGM->BindDC(NULL);

	BLENDFUNCTION bf;
	bf.BlendOp             = AC_SRC_OVER;
	bf.BlendFlags          = 0;
	bf.SourceConstantAlpha = (BYTE)bcg_clamp(m_nPopupAlpha, 0, 255);
	bf.AlphaFormat         = LWA_COLORKEY;

#ifndef _BCGSUITE_
	globalData.UpdateLayeredWindow (GetSafeHwnd (), NULL, 0, &size, dc.GetSafeHdc (), 
		&point, 0, &bf, 0x02);
#else
	UpdateLayeredWindow (NULL, 0, &size, &dc, &point, 0, &bf, 0x02);
#endif

	dc.SelectObject (pBitmapOld);
}
Esempio n. 11
0
//***********************************************************************************************************
BOOL CBCGPBaseVisualCtrl::DoPrint(CDC* pDCIn, CPrintInfo* pInfo)
{
	CObject* pBaseVisual = GetVisualBaseObject();
	if (pBaseVisual == NULL)
	{
		return FALSE;
	}

	CBCGPBaseVisualObject* pVisualObject = DYNAMIC_DOWNCAST(CBCGPBaseVisualObject, pBaseVisual);
	CBCGPVisualContainer* pVisualContainer = DYNAMIC_DOWNCAST(CBCGPVisualContainer, pBaseVisual);

	if (pVisualObject == NULL && pVisualContainer == NULL)
	{
		return FALSE;
	}

	CBCGPGraphicsManager* pGM = GetGraphicsManager();
	if (pGM == NULL)
	{
		return FALSE;
	}

	ASSERT_VALID(pGM);

	CDC* pDC = pDCIn;
	CPrintDialog* pPrintDlg = NULL;

	if (pDC == NULL)
	{
		pPrintDlg = new CPrintDialog(FALSE);
		
		if (pPrintDlg->DoModal() == IDCANCEL)
		{
			delete pPrintDlg;
			return FALSE;
		}

		pDC = CDC::FromHandle(pPrintDlg->GetPrinterDC());
		pDC->m_bPrinting = TRUE;
		
		CString strTitle;
		strTitle.LoadString(AFX_IDS_APP_TITLE);
		
		DOCINFO di;
		ZeroMemory(&di, sizeof (DOCINFO));
		di.cbSize = sizeof (DOCINFO);
		di.lpszDocName = strTitle;
		
		if (!pDC->StartDoc(&di))
		{	
			pDC->AbortDoc();
			delete pPrintDlg;
			return FALSE;
		}

		pInfo = new CPrintInfo();
		pInfo->m_rectDraw.SetRect(0,0, pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
	}

	CSize size(pInfo->m_rectDraw.Size());
	CBCGPRect rect(CBCGPPoint(), size);
	CBCGPRect rectControl(pVisualObject != NULL ? pVisualObject->GetRect() : pVisualContainer->GetRect());

	CBCGPSize sizeScaleRatio((double)size.cx / rectControl.Width(), (double)size.cy / rectControl.Height());

	double dAspect = min(sizeScaleRatio.cx, sizeScaleRatio.cy);
	sizeScaleRatio.cx = sizeScaleRatio.cy = dAspect;

	size.cx = bcg_clamp((int)(rectControl.Width() * dAspect), 0, size.cx);
	size.cy = bcg_clamp((int)(rectControl.Height() * dAspect), 0, size.cy);
	
	rect.SetSize(size);

	CDC	dcPrint;
	CBitmap	bmpPrint;
	CBitmap* pBmpPrintOld = NULL;
	CDC* pDCOut = NULL;

	CBrush brWhite(RGB(255, 255, 255));

	if (DYNAMIC_DOWNCAST(CBCGPGraphicsManagerGDI, pGM) != NULL)
	{
		dcPrint.CreateCompatibleDC(NULL);
		bmpPrint.Attach(CBCGPDrawManager::CreateBitmap_32(size, NULL));
		
		pBmpPrintOld = dcPrint.SelectObject (&bmpPrint);
		ASSERT(pBmpPrintOld != NULL);

		pDCOut = &dcPrint;
	}
	else
	{
		pGM->SetPrintInfo(pInfo);
		pDCOut = pDC;
	}

	pDCOut->FillRect((CRect)rect, &brWhite);
	pGM->BindDC(pDCOut);

	if (pGM->IsBindDCFailed())
	{
		pDCOut->FillRect((CRect)rect, &brWhite);
		pDCOut->TextOut(0, 0, _T("Out of memory"));
	}
	else
	{
		pGM->BeginDraw();

		CBCGPSize sizeScaleRatioOld;
		
		if (pVisualObject != NULL)
		{
			sizeScaleRatioOld = pVisualObject->GetScaleRatio();
			pVisualObject->SetScaleRatio(sizeScaleRatio);
			pVisualObject->SetRect(rect);
		}
		else
		{
			sizeScaleRatioOld = pVisualContainer->GetScaleRatio();
			pVisualContainer->SetScaleRatio(sizeScaleRatio);
			pVisualContainer->SetRect(rect);
		}

		pGM->Clear();

		if (pVisualObject != NULL)
		{
			pVisualObject->OnDraw (pGM, rect);
		}
		else
		{
			pVisualContainer->OnDraw (pGM, rect);
		}

		pGM->EndDraw();

		pGM->BindDC(NULL);

		if (pVisualObject != NULL)
		{
			pVisualObject->SetScaleRatio(sizeScaleRatioOld);
		}
		else
		{
			pVisualContainer->SetScaleRatio(sizeScaleRatioOld);
		}

		if (dcPrint.GetSafeHdc() != NULL)
		{
			CBCGPDrawManager::FillAlpha (rect, (HBITMAP)bmpPrint.GetSafeHandle (), 255);
		}
	}

	if (pVisualObject != NULL)
	{
		pVisualObject->SetRect(rectControl);
		pVisualObject->SetDirty ();
	}
	else
	{
		pVisualContainer->SetRect(rectControl);
		pVisualContainer->SetDirty ();
	}

	if (dcPrint.GetSafeHdc() != NULL)
	{
		BITMAP bmp = {0};
		bmpPrint.GetBitmap (&bmp);

		CRect rectOut(pInfo->m_rectDraw.TopLeft (), CSize(bmp.bmWidth, bmp.bmHeight));

		int mode = pDC->SetStretchBltMode(HALFTONE);

		pDC->BitBlt (rectOut.left, rectOut.top, rectOut.Width(), rectOut.Height(), &dcPrint, 0, 0, SRCCOPY);
		pDC->SetStretchBltMode(mode);

		dcPrint.SelectObject(pBmpPrintOld);
	}
	else
	{
		pGM->SetPrintInfo(NULL);
	}

	if (pPrintDlg != NULL)
	{
		pDC->EndDoc();
		delete pPrintDlg;
		delete pInfo;
	}

	return TRUE;
}
Esempio n. 12
0
//*******************************************************************************
void CBCGPKnob::CreatePointerPoints(double dblRadius,
                                    CBCGPPointsArray& arPoints,
                                    int nPointerIndex, BOOL bShadow)
{
    if (m_rect.IsRectEmpty())
    {
        return;
    }

    CBCGPRect rect = m_rect;

    CBCGPKnobPointer* pData = DYNAMIC_DOWNCAST(CBCGPKnobPointer, m_arData[nPointerIndex]);
    if (pData == NULL)
    {
        ASSERT(FALSE);
        return;
    }

    CBCGPCircularGaugeScale* pScale = GetScale(pData->GetScale());
    if (pScale == NULL)
    {
        ASSERT(FALSE);
        return;
    }

    const double scaleRatio = GetScaleRatioMid();

    double dblValue = pData->IsAnimated() ? pData->GetAnimatedValue() : pData->GetValue();

    double dblOffset = bcg_clamp(pData->GetOffsetFromCenter(), 0.0, 1.0);
    if (dblOffset == 0.0)
    {
        dblOffset = dblRadius * .5;
    }
    else
    {
        dblOffset = dblRadius * bcg_clamp(dblOffset, 0.5, 1.0);
    }

    double dblAngle = bcg_deg2rad(pScale->GetStartAngle()) - bcg_deg2rad(pScale->GetStartAngle() - pScale->GetFinishAngle()) * (dblValue - pScale->GetStart()) / (pScale->GetFinish() - pScale->GetStart());
    dblAngle = bcg_normalize_rad (dblAngle);

    if (bShadow)
    {
        rect.OffsetRect(2 * m_sizeScaleRatio.cx, 2 * m_sizeScaleRatio.cy);
    }

    CBCGPPoint center((rect.left + rect.right) / 2.0, (rect.top + rect.bottom) / 2.0);

    const double angleCos  = cos(dblAngle);
    const double angleSin  = sin(dblAngle);

    double dblWidth = bcg_clamp(pData->GetWidth(), 0.0, dblRadius / 10.0);
    const double dblPointerAngle = dblAngle - M_PI_2;

    switch (pData->GetStyle())
    {
    case CBCGPKnobPointer::BCGP_KNOB_POINTER_HANDLE:
    {
        dblRadius -= .2 * scaleRatio;
        double dblExtend = (dblRadius * .9);
        double dblSize = dblRadius + dblExtend;
        center.x -= angleCos * dblExtend;
        center.y += angleSin * dblExtend;

        if (dblWidth == 0.0)
        {
            dblWidth = dblRadius / 3.0;
        }

        dblWidth *= 0.5;

        if (dblWidth < 1.0)
        {
            arPoints.Add(center);

            arPoints.Add(CBCGPPoint(
                             center.x + angleCos * dblSize,
                             center.y - angleSin * dblSize));
        }
        else
        {
            double dblArrowLen = max(2.0 * dblWidth, 10.0 * scaleRatio);
            dblSize -= dblArrowLen;

            const double dx = cos(dblPointerAngle) * dblWidth;
            const double dy = -sin(dblPointerAngle) * dblWidth;

            arPoints.Add(CBCGPPoint(center.x + dx, center.y + dy));

            arPoints.Add(CBCGPPoint(center.x - dx, center.y - dy));

            const CBCGPPoint pt1(
                center.x + angleCos * dblSize - dx,
                center.y - angleSin * dblSize - dy);

            const CBCGPPoint pt2(
                center.x + angleCos * dblSize + dx,
                center.y - angleSin * dblSize + dy);

            arPoints.Add(pt1);

            arPoints.Add(CBCGPPoint(
                             center.x + angleCos * (dblSize + dblArrowLen),
                             center.y - angleSin * (dblSize + dblArrowLen)));

            arPoints.Add(pt2);
        }
    }
    break;

    case CBCGPKnobPointer::BCGP_KNOB_POINTER_LINE:
    {
        if (bShadow)
        {
            return;
        }

        if (dblWidth == 0.0)
        {
            dblWidth = 2. * scaleRatio;
        }

        const double dx = cos(dblPointerAngle) * dblWidth;
        const double dy = -sin(dblPointerAngle) * dblWidth;

        arPoints.Add(CBCGPPoint(center.x + angleCos * dblOffset - dx, center.y - angleSin * dblOffset - dy));
        arPoints.Add(CBCGPPoint(center.x + angleCos * dblOffset + dx, center.y - angleSin * dblOffset + dy));

        dblOffset = dblRadius - 4. * scaleRatio;

        arPoints.Add(CBCGPPoint(center.x + angleCos * dblOffset + dx, center.y - angleSin * dblOffset + dy));
        arPoints.Add(CBCGPPoint(center.x + angleCos * dblOffset - dx, center.y - angleSin * dblOffset - dy));
    }
    break;

    case CBCGPKnobPointer::BCGP_KNOB_POINTER_CIRCLE:
    {
        if (bShadow)
        {
            return;
        }

        if (dblWidth == 0.0)
        {
            dblWidth = max(2. * scaleRatio, dblRadius / 8);
        }

        dblOffset = dblRadius - 6. * scaleRatio - dblWidth;

        arPoints.Add(CBCGPPoint(center.x + angleCos * dblOffset, center.y - angleSin * dblOffset));
        arPoints.Add(CBCGPPoint(dblWidth, dblWidth));
    }
    break;
    }
}