Click here to Skip to main content
Click here to Skip to main content

Not just a image list control, Neat, 3D, iTunes style

, 29 Oct 2007
Rate this:
Please Sign up or sign in to vote.
The image list controls shows all imaes in 3D, animate the items when selected and let control item size, transparency, positions and animation speed


Download AlbumViewerReleaseDemo.zip - 2,803.1 KB

Download AlbumViewerSrc.zip - 408.7 KB

Screenshot - AlbumViewer.gif

Introduction

The inspiration has been iTunes album list control. This image list control let you display your images in a new 3D manner. No more boring images shown one after another but comes with a cool animation. The zoom level of unselected items can be controls and also the height of shadow, transparency of each unselected item, their position and animation speed.

This is very useful control for displaying images in GUI rich applications. The control is derived from CListCtrl class so it can be extended so support conventional list control views or cool animated 3D view.

Background

As I mentioned the inspiration was iTunes album control. Enjoying music over one of these getting cooler weekends I wondered what would it take to have cool control for showing images with smooth and neat animation as iTunes and hence took up the challenge and found out it only needed some 10 algebra equations and good use of GDI+ to achieve it.


This control loads full size images, in the demo it uses images as large as 800x600 and by using GDI+ efficiently you can animate, zoom and control alpha without any flicker and in a very smooth manner.

This article is most useful for developers looking for more information on using GDI+ painting. Even though GDI+ got almost everything needed but could not get the images to draw like iTunes. It allows to shear the images however doesn't allow to make height of both sides of images different. I did not really try to use matrix transformations however I think the animation and positioning of images could be done better using them.

Using the code

To use the control in your project add AlubumCtrl.h and AlbumCtrl.cpp, add a list control on your form/dialog box, create a member variable for this list control of type CAlbumCtrl and add the following code in your OnInitDialog or anywhere else where you want to add new items to the list control:
    m_ctlAlbum.AddItem(L"images\\Water lilies.jpg");
    m_ctlAlbum.AddItem(L"images\\Sunset.jpg");
    m_ctlAlbum.AddItem(L"images\\Winter.jpg");
    m_ctlAlbum.AddItem(L"images\\Blue hills.jpg");

    m_ctlAlbum.SetCurrentItem(2);

    m_sldAlpha.SetRange(0,100);
    m_sldAnim.SetRange(0,100);
    m_sldShadow.SetRange(0,100);
    m_sldZoom.SetRange(0,100);
    m_sldElevation.SetRange(-300,100);

    m_sldElevation.SetPos(m_ctlAlbum.GetItemElevation());

    m_sldAlpha.SetPos(m_ctlAlbum.GetItemAlpha());
    m_sldAnim.SetPos(m_ctlAlbum.GetAnimSpeed());
    m_sldShadow.SetPos(m_ctlAlbum.GetItemShadow());
    m_sldZoom.SetPos(m_ctlAlbum.GetItemZoom());



Calculating item positions

The following function is most import function in placing the control and suprisingly smallest portion of code. Well it did take some 4 iterations of fine tuning the algebra and code before it came to this Smile | :)

RectF CAlbumCtrl::CalcItemRect(const int n, const RectF rcBase, bool bLeft)
{
    float r = m_fRatio;
    float p = pow(r,n);
    int h = rcBase.Height;
    int w = rcBase.Width;
    int y = 0;
    int x = 0;

    for(int j=1;j<=n;j++)
        y += (m_nItemY*h*pow(r,j))/100;

    if( bLeft )
    {

        int x = 0;
        for(int j=2;j<=n+1;j++)
            x += w*pow(r,j);

        return RectF(rcBase.X-x, rcBase.Y-y, w*p, h*p);
    }
        
    x = rcBase.X + w;

    for(int j=1;j<n;j++)
        x += w*pow(r,j);

    for(int j=1;j<n+1;j++)
        x -= (1-r)*w*pow(r,j);

    return RectF(x, rcBase.Y-y, w*p, h*p);
}

Drawing items

This is second most important function in the control. This picks up the items image, calculates the shadow width, applies alpha to image and decreasing alpha to the shadow and if required places text over selected images.

void CAlbumCtrl::DrawItem(const int nItem, RectF rc, Graphics &grf, float fAlpha, bool bDrawText)
{
    // centre image
    // draw the items only if they are inside the visible area
    // to keep repainting fast

    if( nItem < 0 || nItem > m_vecItems.size()-1 )
        return;

    Bitmap bitmap(m_vecItems[nItem].wszItem.c_str());

    CRect r;
    GetClientRect(&r);

    RectF rcWnd(r.left, r.top, r.Width(), r.Height());
    if(!rcWnd.IntersectsWith(rc))
        return;

    Bitmap     bmp(rc.Width, rc.Height, PixelFormat32bppARGB );

    Graphics graphic(&bmp);

    ImageAttributes imgAttrb;

    RectF rcDraw(0, 0, rc.Width, rc.Height);
    graphic.DrawImage(&bitmap, rcDraw, 0, 0, bitmap.GetWidth(), bitmap.GetHeight(), UnitPixel, &imgAttrb);

    graphic.DrawRectangle(&Pen(Color(80,80,80), 2),rcDraw);
    
    ColorMatrix bmpAlpha = {
                             1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
                             0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
                             0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
                             0.0f, 0.0f, 0.0f, fAlpha, 0.0f,
                             0.0f, 0.0f, 0.0f, 0.0f, 1.0f
                            };


    imgAttrb.SetColorMatrix(&bmpAlpha);
    grf.DrawImage(&bmp, rc, 0, 0, rc.Width, rc.Height, UnitPixel, &imgAttrb);

    int iHeight = bmp.GetHeight();
    int iWidth = bmp.GetWidth();

    // reflection percent

    if( !m_nItemShadow )
        m_nItemShadow = 1;

    float nRef = 100.0/m_nItemShadow;
    RectF rcRef = RectF(rc.X, rc.Y+rc.Height, rc.Width, rc.Height/nRef);
    Bitmap     bmpRef(rcDraw.Width, rcDraw.Height/nRef, PixelFormat32bppARGB );

    Color color, colorTemp;
    for(UINT iRow = iHeight; iRow > iHeight-iHeight/nRef; iRow--)
    {
       for(UINT iColumn = 0; iColumn < iWidth; iColumn++)
       {
           // decrease the alpha by 1 value for each line in bottom margin
           double dAlpha = (iHeight/nRef-(iHeight-iRow))*255/(iHeight/nRef);
          bmp.GetPixel(iColumn, iRow, &color);
          colorTemp.SetValue(color.MakeARGB(
             //(BYTE)(5*(iHeight/nRef-(iHeight-iRow))), 
             (BYTE)dAlpha,
             color.GetRed(),
             color.GetGreen(),
             color.GetBlue()));
          bmpRef.SetPixel(iColumn, iHeight-iRow, colorTemp);
       }
    }
    grf.DrawImage(&bmpRef, rcRef, 0, 0, rcRef.Width, rcRef.Height, 
    UnitPixel, &imgAttrb);
    if( bDrawText )
    {
        //wstring wszText = m_vecItems[nItem].wszItem; 
        //Font myFont(L"Tahoma",12,FontStyleRegular,UnitPixel);
        //
        //RectF rcText;
        //grf.MeasureString(wszText.c_str(), wszText.length(), &myFont, 
    // rcRef, &rcText);
        //grf.DrawString(wszText.c_str(),wszText.length(), &myFont, 
    // PointF(rcRef.X+rcRef.Width-rcText.Width-14, 
    // rcRef.Y+(rcRef.Height-rcText.Height)/2-rcText.Height), 
    // &SolidBrush(Color(255,255,255))); 
        //wchar_t temp[10];
        //wszText = _itow(nItem+1, temp, 10);
        //grf.DrawString(wszText.c_str(),wszText.length(), &myFont, 
    // PointF(rcRef.X+2, rcRef.Y+(rcRef.Height-rcText.Height)/2-rcText.Height), 
    // &SolidBrush(Color(255,255,255))); 
        //grf.DrawString(wszText.c_str(),wszText.length(), &myFont, 
    // PointF(rcRef.X, rcRef.Y), &SolidBrush(Color(255,255,255))); 
    }
}

Behind the scenes involved maths

The most interested portion of the control is the maths involved in positioning and animating the items. In that there is different algebra involved in placing/animating the items on the left and right of the center selected item.

Position the items in the control

Calculating the width of any item

Wn = W (r/100)n

Calculating the height of any item

Hn = H (r/100)n

Calculating the Y position of any item

Yn = Y - n

i = 1
H/e(r/100)

Calculating the X position of items on the left of selected item

Xn = X - n+1

i = 2
W(r/100)

Calculating the X position of items on the right of selected item

Xn = X + W + n-1

i = 1
W(r/100)i - n+1

i = 1
W(1-r/100)(r/100)

where

H = Height of the selected item

W = Width of the selected item

X = X position of the selected item

Y = Y position of the selected item

r = Current zoom level in %

e = Current elevation of Y


Animating items in the control

Animating items towards the left

Animating items on the left side

∆X = c(Xn+1-Xn)/l
Xn = Xn + ∆X

∆Y = c(Yn+1-Yn)/l

Yn = Yn + ∆Y


∆W = c(Wn+1-Wn)/l
Wn = Wn + ∆W

∆H = c(Hn+1-Hn)/l
Hn = Hn + ∆H

Animating items on the right side

∆X = c(Xn+1-Xn)/l
Xn-1 = Xn + ∆X

∆Y = c(Yn+1-Yn)/l
Yn-1 = Yn - ∆Y

∆W = c(Wn+1-Wn)/l
Wn = Wn - ∆W

∆H = c(Hn+1-Hn)/l
Hn = Hn - ∆H

Animating items towards the right

Animating items on the left side



∆X = c(Xn+1-Xn)/l
Xn = Xn + ∆X

∆Y = c(Yn+1-Yn)/l

Yn = Yn + ∆Y


∆W = c(Wn+1-Wn)/l
Wn = Wn + ∆W

∆H = c(Hn+1-Hn)/l
Hn = Hn + ∆H

Animating items on the right side


∆X = c(Xn+1-Xn)/l
Xn = Xn + ∆X

∆Y = c(Yn+1-Yn)/l
Yn = Yn - ∆Y

∆W = c(Wn-1-Wn)/l
Wn = Wn - ∆W

∆H = c(Hn-1-Hn)/l
Hn = Hn - ∆H

Where

c = Current animation step

l = Total animation steps count



Future Features

Planning to add view switch buttons so users can switch back/forth to Icon view/List View/Report View/Album View

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ashok Jaiswal
Web Developer
Hong Kong Hong Kong
innovating, managing and developing next generation media products and services

Comments and Discussions

 
GeneralMy vote of 1 Pinmembersaravanan.rex@gmail.com6-Apr-09 19:59 
Generalcool PinmemberDr.Luiji13-Nov-07 20:47 
GeneralRe: cool PinmemberAshok Jaiswal14-Nov-07 16:50 
GeneralRe: cool PinmemberDr.Luiji15-Nov-07 10:15 
QuestionBarking up the wrong tree? Pinmemberazonenberg8-Nov-07 4:19 
AnswerRe: Barking up the wrong tree? PinmemberAshok Jaiswal14-Nov-07 16:51 
GeneralPretty much unusable PinmemberScope30-Oct-07 4:09 
GeneralRe: Pretty much unusable PinmemberAshok Jaiswal30-Oct-07 7:47 
GeneralToo wide PinmvpDavidCrow29-Oct-07 10:29 
GeneralRe: Too wide PinmemberAshok Jaiswal29-Oct-07 10:34 
QuestionWhat improvement!! PinmemberJohn A. Johnson25-Oct-07 5:24 
AnswerRe: What improvement!! PinmemberAshok Jaiswal25-Oct-07 7:46 
GeneralExcellent Article Pinmemberrajantawate1(http//www.jhatak.com)24-Oct-07 5:19 
GeneralRe: Excellent Article PinmemberAshok Jaiswal24-Oct-07 7:19 
GeneralRe: Excellent Article PinmemberNarendraSinghJTV8-Oct-09 1:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140827.1 | Last Updated 29 Oct 2007
Article Copyright 2007 by Ashok Jaiswal
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid