{"id":4943,"date":"2013-03-15T07:00:00","date_gmt":"2013-03-15T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/03\/15\/playing-with-the-windows-animation-manager-moving-lots-of-stuff-around\/"},"modified":"2013-03-15T07:00:00","modified_gmt":"2013-03-15T07:00:00","slug":"playing-with-the-windows-animation-manager-moving-lots-of-stuff-around","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20130315-00\/?p=4943","title":{"rendered":"Playing with the Windows Animation Manager: Moving lots of stuff around"},"content":{"rendered":"<p><P>\n<A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/03\/14\/10399699.aspx\">\nWe saw last time<\/A>\na sample program that moved a circle around.\nToday I&#8217;ll try to build the classic demo of animating a lot of\nobjects in a list.\n<\/P>\n<P>\nThis isn&#8217;t the prettiest code, but I wanted to make as few changes\nas possible.\nStart with the\n<A HREF=\"http:\/\/archive.msdn.microsoft.com\/animationmanager\">\nTimer-Driven Animation<\/A>,\nand make these changes to the\n<CODE>Main&shy;Window.h<\/CODE> header file.\n<\/P>\n<PRE>\n<FONT COLOR=\"blue\">struct Item\n{\n    IUIAnimationVariable *m_pAnimationVariableX;\n    IUIAnimationVariable *m_pAnimationVariableY;\n    Gdiplus::Color m_color;\n};<\/FONT><\/p>\n<p>class MainWindow\n{\n    &#8230;<\/p>\n<p>    <FONT COLOR=\"red\">\/\/ <STRIKE>HRESULT ChangeColor(<\/STRIKE><\/FONT>\n    <FONT COLOR=\"red\">\/\/     <STRIKE>DOUBLE red,<\/STRIKE><\/FONT>\n    <FONT COLOR=\"red\">\/\/     <STRIKE>DOUBLE green,<\/STRIKE><\/FONT>\n    <FONT COLOR=\"red\">\/\/     <STRIKE>DOUBLE blue<\/STRIKE><\/FONT>\n    <FONT COLOR=\"red\">\/\/     <STRIKE>);<\/STRIKE><\/FONT>\n    <FONT COLOR=\"blue\">HRESULT ChangePos();<\/FONT><\/p>\n<p>    &#8230;\nprivate:<\/p>\n<p>    <FONT COLOR=\"blue\">static const int ItemCount = 100;\n    static const int ItemWidth = 40;\n    static const int ItemHeight = 40;\n    static int XFromIndex(int index)\n    {\n        return (index % 10) * 50;\n    }\n    static int YFromIndex(int index)\n    {\n        return (index \/ 10) * 50;\n    }<\/FONT><\/p>\n<p>    &#8230;<\/p>\n<p>    <FONT COLOR=\"red\">\/\/ <STRIKE>IUIAnimationVariable *m_pAnimationVariableRed;<\/STRIKE><\/FONT>\n    <FONT COLOR=\"red\">\/\/ <STRIKE>IUIAnimationVariable *m_pAnimationVariableGreen;<\/STRIKE><\/FONT>\n    <FONT COLOR=\"red\">\/\/ <STRIKE>IUIAnimationVariable *m_pAnimationVariableBlue;<\/STRIKE><\/FONT>\n    <FONT COLOR=\"blue\">Item m_Items[ItemCount];<\/FONT>\n};\n<\/PRE>\n<P>\nFrom the changes in the header file,\nI think you see where this is going.\nInstead of just having one item on the screen,\nI&#8217;m going to put a hundred.\n<\/P>\n<P>\nHere are the changes to\n<CODE>Main&shy;Window.cpp<\/CODE>.\nFirst, we need to null out our pointers at construction\nand clean them up at destruction.\n(This sample program does not use smart pointers,\nso I won&#8217;t either.)\n<\/P>\n<PRE>\nCMainWindow::CMainWindow() :\n    m_hwnd(NULL),\n    m_pAnimationManager(NULL),\n    m_pAnimationTimer(NULL),\n    m_pTransitionLibrary(NULL)<FONT COLOR=\"red\">\/\/ <STRIKE>,<\/STRIKE><\/FONT>\n    <FONT COLOR=\"red\">\/\/ <STRIKE>m_pAnimationVariableRed(NULL),<\/STRIKE><\/FONT>\n    <FONT COLOR=\"red\">\/\/ <STRIKE>m_pAnimationVariableGreen(NULL),<\/STRIKE><\/FONT>\n    <FONT COLOR=\"red\">\/\/ <STRIKE>m_pAnimationVariableBlue(NULL)<\/STRIKE><\/FONT>\n{\n    <FONT COLOR=\"blue\">for (int i = 0; i &lt; ItemCount; i++)\n    {\n        m_Items[i].m_pAnimationVariableX = NULL;\n        m_Items[i].m_pAnimationVariableY = NULL;\n    }<\/FONT>\n}<\/p>\n<p>CMainWindow::~CMainWindow()\n{\n    \/\/ Animated Variables\n    <FONT COLOR=\"red\">\/\/ <STRIKE>SafeRelease(&amp;m_pAnimationVariableRed);<\/STRIKE><\/FONT>\n    <FONT COLOR=\"red\">\/\/ <STRIKE>SafeRelease(&amp;m_pAnimationVariableGreen);<\/STRIKE><\/FONT>\n    <FONT COLOR=\"red\">\/\/ <STRIKE>SafeRelease(&amp;m_pAnimationVariableBlue);<\/STRIKE><\/FONT>\n    <FONT COLOR=\"blue\">for (int i = 0; i &lt; ItemCount; i++)\n    {\n        SafeRelease(&amp;m_Items[i].m_pAnimationVariableX);\n        SafeRelease(&amp;m_Items[i].m_pAnimationVariableY);\n    }<\/FONT><\/p>\n<p>    &#8230;\n}<\/p>\n<p><\/PRE>\n<P>\nNext we get rid of the initial animation.\n<\/P>\n<PRE>\nHRESULT CMainWindow::Initialize(\n    HINSTANCE hInstance                            \n    )\n{\n    &#8230;\n                <FONT COLOR=\"red\">\/\/ <STRIKE>Fade in with Red<\/STRIKE><\/FONT>\n                <FONT COLOR=\"red\">\/\/ <STRIKE>hr = ChangeColor(COLOR_MAX, COLOR_MIN, COLOR_MIN);<\/STRIKE><\/FONT>\n    &#8230;\n}\n<\/PRE>\n<P>\nAs you might expect, the <CODE>Create&shy;Animation&shy;Variables<\/CODE>\nmethod changed completely, since it now has to create the variables\nfor each item.\nBut the basic idea is the same:\nCreate each variable with the appropriate initial value.\n(It&#8217;s also a lot shorter!)\n<\/P>\n<PRE>\nHRESULT CMainWindow::CreateAnimationVariables()\n{\n    <FONT COLOR=\"blue\">HRESULT hr = S_OK;<\/p>\n<p>    for (int i = 0; SUCCEEDED(hr) &amp;&amp; i &lt; ItemCount; i++)\n    {\n        m_Items[i].m_color = Color(\n            static_cast&lt;BYTE&gt;(RandomFromRange(COLOR_MIN, COLOR_MAX)),\n            static_cast&lt;BYTE&gt;(RandomFromRange(COLOR_MIN, COLOR_MAX)),\n            static_cast&lt;BYTE&gt;(RandomFromRange(COLOR_MIN, COLOR_MAX))\n        );\n        hr = m_pAnimationManager-&gt;CreateAnimationVariable(\n            XFromIndex(i),\n            &amp;m_Items[i].m_pAnimationVariableX\n        );\n        if (SUCCEEDED(hr))\n        {\n            hr = m_pAnimationManager-&gt;CreateAnimationVariable(\n            YFromIndex(i),\n                &amp;m_Items[i].m_pAnimationVariableY\n                );\n        }\n    }<\/FONT><\/p>\n<p>    return hr;\n}\n<\/PRE>\n<P>\nThe <CODE>Draw&shy;Background<\/CODE> method is becoming\nincreasingly inaccurately-named,\nsince in addition to drawing the background, we also draw\nthe foreground!\n<\/P>\n<PRE>\nHRESULT CMainWindow::DrawBackground(\n    Graphics &amp;graphics,\n    const RectF &amp;rectPaint\n    )\n{\n    <FONT COLOR=\"blue\">SolidBrush brushBackground(Color(255, 255, 255));\n    HRESULT<\/FONT> hr = HrFromStatus(graphics.FillRectangle(\n            &amp;brushBackground,\n            rectPaint\n            ));<\/p>\n<p>    <FONT COLOR=\"blue\">for (int i = 0; SUCCEEDED(hr) &amp;&amp; i &lt; ItemCount; i++)\n    {\n        INT32 x;\n        hr = m_Items[i].m_pAnimationVariableX-&gt;GetIntegerValue(\n            &amp;x\n            );\n        if (SUCCEEDED(hr))\n        {\n            INT32 y;\n            hr = m_Items[i].m_pAnimationVariableY-&gt;GetIntegerValue(\n                &amp;y\n                );\n            if (SUCCEEDED(hr))\n            {\n                SolidBrush brush(m_Items[i].m_color);\n                RectF rectItem(\n                    static_cast&lt;REAL&gt;(x),\n                    static_cast&lt;REAL&gt;(y),\n                    static_cast&lt;REAL&gt;(ItemWidth),\n                    static_cast&lt;REAL&gt;(ItemHeight));\n                hr = HrFromStatus(graphics.FillRectangle(\n                    &amp;brush,\n                    rectItem\n                    ));\n            }\n        }\n    }<\/FONT><\/p>\n<p>    return hr;\n}\n<\/PRE>\n<P>\nWe change what happens when you click the left mouse button.\nInstead of changing the color, we shuffle the items randomly.\n<\/P>\n<PRE>\nHRESULT CMainWindow::OnLButtonDown()\n{\n    HRESULT hr = <FONT COLOR=\"blue\">ChangePos();<\/FONT><\/p>\n<p>    return hr; \n}\n<\/PRE>\n<P>\nAnd now the money function:\nShuffling the items and animating them to their new locations.\n<\/P>\n<PRE>\nHRESULT CMainWindow::<FONT COLOR=\"blue\">ChangePos()<\/FONT>\n{\n    const UI_ANIMATION_SECONDS DURATION = 0.5;\n    const DOUBLE ACCELERATION_RATIO = 0.5;\n    const DOUBLE DECELERATION_RATIO = 0.5;<\/p>\n<p>    <FONT COLOR=\"blue\">\/\/ Assign final locations randomly\n    int Destination[ItemCount];\n    Destination[0] = 0;\n    for (int i = 1; i &lt; ItemCount; i++)\n    {\n        int j = rand() % (i + 1);\n        Destination[i] = Destination[j];\n        Destination[j] = i;\n    }<\/FONT><\/p>\n<p>    \/\/ Create a storyboard<\/p>\n<p>    IUIAnimationStoryboard *pStoryboard = NULL;\n    HRESULT hr = m_pAnimationManager-&gt;CreateStoryboard(\n        &amp;pStoryboard\n        );\n    if (SUCCEEDED(hr))\n    {\n        <FONT COLOR=\"blue\">for (int i = 0; SUCCEEDED(hr) &amp;&amp; i &lt; ItemCount; i++)\n        {<\/FONT>\n            \/\/ Create transitions for the <FONT COLOR=\"blue\">position<\/FONT> animation variables<\/p>\n<p>            IUIAnimationTransition *pTransition<FONT COLOR=\"blue\">X<\/FONT>;\n            hr = m_pTransitionLibrary-&gt;CreateAccelerateDecelerateTransition(\n                DURATION,\n                <FONT COLOR=\"blue\">XFromIndex(Destination[i])<\/FONT>,\n                ACCELERATION_RATIO,\n                DECELERATION_RATIO,\n                &amp;pTransition<FONT COLOR=\"blue\">X<\/FONT>\n                );<\/p>\n<p>            if (SUCCEEDED(hr))\n            {\n                IUIAnimationTransition *pTransition<FONT COLOR=\"blue\">Y<\/FONT>;\n                hr = m_pTransitionLibrary-&gt;CreateAccelerateDecelerateTransition(\n                    DURATION,\n                    <FONT COLOR=\"blue\">YFromIndex(Destination[i])<\/FONT>,\n                    ACCELERATION_RATIO,\n                    DECELERATION_RATIO,\n                    &amp;pTransition<FONT COLOR=\"blue\">Y<\/FONT>\n                );<\/p>\n<p>                \/\/ <FONT COLOR=\"red\">Delete &#8220;blue&#8221; transition<\/FONT><\/p>\n<p>                if (SUCCEEDED(hr))\n                {\n                    \/\/ Add transitions to the storyboard<\/p>\n<p>                    hr = pStoryboard-&gt;AddTransition(\n                        <FONT COLOR=\"blue\">m_Items[i].<\/FONT>m_pAnimationVariable<FONT COLOR=\"blue\">X<\/FONT>,\n                        pTransition<FONT COLOR=\"blue\">X<\/FONT>\n                        );\n                    if (SUCCEEDED(hr))\n                    {\n                        hr = pStoryboard-&gt;AddTransition(\n                            <FONT COLOR=\"blue\">m_Items[i].<\/FONT>m_pAnimationVariable<FONT COLOR=\"blue\">Y<\/FONT>,\n                            pTransition<FONT COLOR=\"blue\">Y<\/FONT>\n                            );\n                        \/\/ <FONT COLOR=\"red\">Delete &#8220;blue&#8221; transition<\/FONT>\n                        \/\/ <FONT COLOR=\"red\">Move &#8220;Schedule&#8221; out of the loop<\/FONT>\n                    }<\/p>\n<p>                    pTransition<FONT COLOR=\"blue\">Y<\/FONT>-&gt;Release();\n                }<\/p>\n<p>                pTransition<FONT COLOR=\"blue\">X<\/FONT>-&gt;Release();\n            }\n        }<\/p>\n<p>        <FONT COLOR=\"blue\">\/\/ Scheduling code moved outside the loop<\/FONT>\n        if (SUCCEEDED(hr))\n        {\n            \/\/ Get the current time and schedule the storyboard for play<\/p>\n<p>            UI_ANIMATION_SECONDS secondsNow;\n            hr = m_pAnimationTimer-&gt;GetTime(\n                &amp;secondsNow\n                );\n            if (SUCCEEDED(hr))\n            {\n                hr = pStoryboard-&gt;Schedule(\n                    secondsNow\n                    );\n            }\n        }<\/p>\n<p>        pStoryboard-&gt;Release();\n    }<\/p>\n<p>    return hr;\n}\n<\/PRE>\n<P>\nIt looked like a lot of code, but really wasn&#8217;t.\nThe only real change was to add the shuffling code\nand to put a loop around the code that generates\nthe transitions and adds them to the storyboard.\n<\/P>\n<P>\nAnd there you have it,\na program that smoothly animates 100 items\neach time you click on the window.\nFor me, the fun thing to do is to\njust click repeatedly on the window and\nwatch the items swirl around like a swarm of insects.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>We saw last time a sample program that moved a circle around. Today I&#8217;ll try to build the classic demo of animating a lot of objects in a list. This isn&#8217;t the prettiest code, but I wanted to make as few changes as possible. Start with the Timer-Driven Animation, and make these changes to the [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-4943","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>We saw last time a sample program that moved a circle around. Today I&#8217;ll try to build the classic demo of animating a lot of objects in a list. This isn&#8217;t the prettiest code, but I wanted to make as few changes as possible. Start with the Timer-Driven Animation, and make these changes to the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/4943","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=4943"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/4943\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=4943"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=4943"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=4943"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}