Windows/MFC

DrawGradient

aucd29 2013. 10. 2. 18:10
[code]여차하면 GDI+를 사용하겠지만 그래도 Gradient가 어떻게 만들어지는 지 알고 있으면 좋을 테니 말이지[/code]

[code]
/////////////////////////////////////////////////////////////////////////////
/*
    DrawGradient

    Called from OnPaint, it does most of the work of filling in the client
    rectangle with the appropriate colors. The normal routine would fill
    the entire client rectangle, but we truncate the drawing to reflect
    the current position in the progress control

    Params
        pDC            pointer to CPaintDC for rendering
        rectClient    client rectangle where we should draw
        nMaxWidth    where we should stop drawing the gradient
*/
/////////////////////////////////////////////////////////////////////////////
void CGradientProgressCtrl::DrawGradient(CPaintDC *pDC, const RECT &rectClient, const int &nMaxWidth, const BOOL &bVertical)
{
    RECT rectFill;             // Rectangle for filling band
    float fStep;             // How wide is each band?
    CBrush brush;            // Brush to fill in the bar    

    
    CMemDC memDC(pDC);

    // First find out the largest color distance between the start and end colors. This distance
    // will determine how many steps we use to carve up the client region and the size of each
    // gradient rect.
    int r, g, b;                    // First distance, then starting value
    float rStep, gStep, bStep;        // Step size for each color
        
    BOOL bSameColor = FALSE;        // Handle case if start color == end color

    // Get the color differences
    r = (GetRValue(m_clrEnd) - GetRValue(m_clrStart));
    g = (GetGValue(m_clrEnd) - GetGValue(m_clrStart));
    b = (GetBValue(m_clrEnd) - GetBValue(m_clrStart));

    // Check to see if colors are same
    if((r == 0) && (g == 0) && (b == 0))
    {
        bSameColor = TRUE;
        //Added the three lines below to fix the drawing
        //problem which used to occur when both the start
        //and end colors are same.
        r = GetRValue(m_clrStart);
        g = GetGValue(m_clrStart);
        b = GetBValue(m_clrStart);
    }

    int nSteps;
    //Select max. possible value for nSteps if the colors are equal
    if(bSameColor && m_clrStart == 0)
        nSteps = 255;
    else     // Make the number of steps equal to the greatest distance
        nSteps = max(abs(r), max(abs(g), abs(b)));    
    
    // Determine how large each band should be in order to cover the
    // client with nSteps bands (one for every color intensity level)
    if (bVertical)
        fStep = (float)rectClient.bottom / (float)nSteps;    
    else
        fStep = (float)rectClient.right / (float)nSteps;

    // Calculate the step size for each color
    rStep = r/(float)nSteps;
    gStep = g/(float)nSteps;
    bStep = b/(float)nSteps;

    // Reset the colors to the starting position
    r = GetRValue(m_clrStart);
    g = GetGValue(m_clrStart);
    b = GetBValue(m_clrStart);
    
    // Start filling bands
    for (int iOnBand = 0; iOnBand < nSteps; iOnBand++)
    {
        // Fill the vertical control
        if (bVertical)
        {
            ::SetRect(&rectFill,
                        0,                            // Upper left X
                        (int)(iOnBand * fStep),        // Upper left Y
                        rectClient.right+1,        // Lower right X
                        (int)((iOnBand+1) * fStep));// Lower right Y
        
            // CDC::FillSolidRect is faster, but it does not handle 8-bit color depth
            VERIFY(brush.CreateSolidBrush(RGB(r+rStep*iOnBand, g + gStep*iOnBand, b + bStep *iOnBand)));
            memDC.FillRect(&rectFill,&brush);
            VERIFY(brush.DeleteObject());


            // If we are past the maximum for the current position we need to get out of the loop.
            // Before we leave, we repaint the remainder of the client area with the background color.
            if (rectFill.bottom > nMaxWidth)
            {
                ::SetRect(&rectFill, 0, rectFill.bottom, rectClient.right, rectClient.bottom);
                VERIFY(brush.CreateSolidBrush(m_clrBkGround));
                memDC.FillRect(&rectFill, &brush);
                VERIFY(brush.DeleteObject());
                return;
            }
        }

        else // Fill the horizontal control
        {
            ::SetRect(&rectFill,
                        (int)(iOnBand * fStep),     // Upper left X
                         0,                            // Upper left Y
                        (int)((iOnBand+1) * fStep), // Lower right X
                        rectClient.bottom+1);        // Lower right Y
        
            // CDC::FillSolidRect is faster, but it does not handle 8-bit color depth
            VERIFY(brush.CreateSolidBrush(RGB(r+rStep*iOnBand, g + gStep*iOnBand, b + bStep *iOnBand)));
            memDC.FillRect(&rectFill,&brush);
            VERIFY(brush.DeleteObject());


            // If we are past the maximum for the current position we need to get out of the loop.
            // Before we leave, we repaint the remainder of the client area with the background color.
            if (rectFill.right > nMaxWidth)
            {
                ::SetRect(&rectFill, rectFill.right, 0, rectClient.right, rectClient.bottom);
                VERIFY(brush.CreateSolidBrush(m_clrBkGround));
                memDC.FillRect(&rectFill, &brush);
                VERIFY(brush.DeleteObject());
                return;
            }
        }

    }
}[/code]