/*++ Copyright (C) 1996-1999 Microsoft Corporation Module Name: scale.cpp Abstract: Implements display of the scale numbers on the graph y-axis. --*/ #include "polyline.h" #include #define SCALE_MARGIN 10 CGraphScale::CGraphScale( void ) : m_iMaxValue(100), m_iMinValue(0), m_nTics(0), m_iTextHeight(0) { } CGraphScale::~CGraphScale( void ) { } void CGraphScale::SetRect( PRECT pRect ) { m_Rect = *pRect; SetTicPositions(); } void CGraphScale::SetMaxValue( INT iMaxValue ) { m_iMaxValue = iMaxValue; SetTicPositions(); } void CGraphScale::SetMinValue( INT iMinValue ) { m_iMinValue = iMinValue; SetTicPositions(); } void CGraphScale::SetTicPositions( void ) { INT iHeight; INT nMaxTics; INT i; CStepper stepper; static INT aiTicTable[] = {25,20,10,5,4,2,1,0}; iHeight = m_Rect.bottom - m_Rect.top; if (!(iHeight > 0 && m_iTextHeight > 0)) { m_nTics = 0; return; } // Determine number of labels that will fit nMaxTics = iHeight / (m_iTextHeight + m_iTextHeight/2); for (i=0; nMaxTics < aiTicTable[i]; i++) {}; m_nTics = aiTicTable[i]; // Don't have more labels than values if (m_iMaxValue - m_iMinValue < m_nTics) m_nTics = m_iMaxValue - m_iMinValue; // Locate equally spaced tic marks if (m_nTics > 0) { m_aiTicPos[0] = 0; stepper.Init(iHeight,m_nTics); for (i = 1; i <= m_nTics; i++) { m_aiTicPos[i] = stepper.NextPosition(); } } } INT CGraphScale::GetTicPositions( INT **piTics ) { *piTics = m_aiTicPos; return m_nTics; } INT CGraphScale::GetWidth (HDC hDC) { WCHAR szMaxValue [MAX_VALUE_LEN] ; SIZE Size; INT iWidth; // compute size of largest possible numerical label plus space if ( 0 != FormatNumber ( (double)m_iMaxValue, szMaxValue, MAX_VALUE_LEN, eMinimumWidth, eFloatPrecision) ) { GetTextExtentPoint32(hDC, szMaxValue, lstrlen(szMaxValue), &Size); // Save Text height for tic calculations m_iTextHeight = Size.cy; iWidth = Size.cx + SCALE_MARGIN; } else { iWidth = 0; } return iWidth; } void CGraphScale::Draw (HDC hDC) { WCHAR szScale [MAX_VALUE_LEN] ; INT iRetChars, i, iUnitsPerLine ; INT iRange; FLOAT ePercentOfTotal ; FLOAT eDiff ; BOOL bUseFloatingPt = FALSE ; RECT rectClip; // nTicks may be zero if the screen size if getting too small if (m_nTics < 1 || m_iMaxValue <= m_iMinValue) return; iRange = m_iMaxValue - m_iMinValue; // Calculate what percentage of the total each line represents. ePercentOfTotal = ((FLOAT) 1.0) / ((FLOAT) m_nTics) ; // Calculate the amount (number of units) of the Vertical max each // each line in the graph represents. iUnitsPerLine = (INT) ((FLOAT) iRange * ePercentOfTotal) ; ePercentOfTotal *= (FLOAT) iRange; eDiff = (FLOAT)iUnitsPerLine - ePercentOfTotal ; if (eDiff < (FLOAT) 0.0) eDiff = -eDiff ; if ( (iUnitsPerLine < 100) && (eDiff > (FLOAT) 0.1) ) { bUseFloatingPt = TRUE ; } SetTextAlign (hDC, TA_TOP | TA_RIGHT) ; rectClip.left = m_Rect.left; rectClip.right = m_Rect.right - SCALE_MARGIN; // Now Output each string. for (i = 0; i < m_nTics; i++) { if (bUseFloatingPt) { FLOAT fValue = (FLOAT)m_iMaxValue - ((FLOAT)i * ePercentOfTotal); iRetChars = FormatNumber ( (double)fValue, szScale, MAX_VALUE_LEN, eMinimumWidth, eFloatPrecision); } else { iRetChars = StringCchPrintf (szScale, MAX_VALUE_LEN, L"%d", m_iMaxValue - (i * iUnitsPerLine)) ; } rectClip.top = m_aiTicPos[i] + m_Rect.top - m_iTextHeight/2; rectClip.bottom = rectClip.top + m_iTextHeight; ExtTextOut ( hDC, rectClip.right, rectClip.top, 0, &rectClip, szScale, lstrlen(szScale), NULL ); } // Make sure the last value is the specified Minimum. if (bUseFloatingPt) { iRetChars = FormatNumber ( (double)m_iMinValue, szScale, MAX_VALUE_LEN, eMinimumWidth, eFloatPrecision); } else { iRetChars = StringCchPrintf (szScale, MAX_VALUE_LEN, L"%d", m_iMinValue) ; } rectClip.top = m_aiTicPos[i] + m_Rect.top - m_iTextHeight/2; rectClip.bottom = rectClip.top + m_iTextHeight; ExtTextOut ( hDC, rectClip.right, rectClip.top, 0, &rectClip, szScale, lstrlen(szScale), NULL); }