{"id":3943,"date":"2013-07-01T07:00:00","date_gmt":"2013-07-01T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/07\/01\/building-on-our-program-that-draws-content-at-a-fixed-screen-position-regardless-of-window-position\/"},"modified":"2013-07-01T07:00:00","modified_gmt":"2013-07-01T07:00:00","slug":"building-on-our-program-that-draws-content-at-a-fixed-screen-position-regardless-of-window-position","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20130701-00\/?p=3943","title":{"rendered":"Building on our program that draws content at a fixed screen position regardless of window position"},"content":{"rendered":"<p>\nToday&#8217;s Little Program\nuses the technique we saw last week of\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/06\/24\/10428001.aspx\">\ndrawing content at a fixed screen position, regardless of window position<\/a>,\nbut adds a little physics to it.\n<\/p>\n<p>\nStart with our\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/07\/23\/54576.aspx\">\nscratch program<\/a>\nand make these changes:\n<\/p>\n<pre>\n#include &lt;math.h&gt; \/\/ physics requires math (go figure)\n#define Omega 2.0f\nclass Motion\n{\npublic:\n Motion() : x0(0.0f), v0(0.0f) { RecalcCurve(); }\n void ShiftOrigin(double dx)\n {\n  Tick();\n  v0 = v;\n  x0 = x + dx;\n  RecalcCurve();\n }\n double Pos() { return x; }\n bool Moving() { return fabs(x) &gt;= 0.5f || fabs(v) &gt;= 1.0f; }\n void Tick() {\n  t = (GetTickCount() - tm0) \/ 1000.0f;\n  double ewt = exp(-Omega * t);\n  double abt = A + B * t;\n  x = abt * ewt;\n  v = (-Omega * abt + B) * ewt;\n }\nprivate:\n void RecalcCurve() {\n  A = x0;\n  B = v0 + Omega * x0;\n  tm0 = GetTickCount();\n }\npublic:\n DWORD tm0;\n double x0, v0, A, B, t, x, v;\n};\n<\/pre>\n<p>\nThe <code>Motion<\/code> class simulates damped motion.\nAsk a physicist how it works.\n<\/p>\n<pre>\nMotion g_mX;  \/\/ motion in x-direction\nMotion g_mY;  \/\/ motion in y-direction\nPOINT g_ptRest; \/\/ desired rest point\nPOINT CalcRestPoint(HWND hwnd)\n{\n    RECT rc;\n    GetClientRect(hwnd, &amp;rc);\n    MapWindowRect(hwnd, HWND_DESKTOP, &amp;rc);\n    POINT pt = { rc.left + (rc.right - rc.left) \/ 2,\n                 rc.top + (rc.bottom - rc.top) \/ 2 };\n    return pt;\n}\n<\/pre>\n<p>\nThe rest point is the center of the window.\n<\/p>\n<pre>\nvoid ScheduleFrame(HWND hwnd)\n{\n    InvalidateRect(hwnd, 0, TRUE);\n    KillTimer(hwnd, 1);\n}\nVOID CALLBACK InvalidateMe(HWND hwnd, UINT, UINT_PTR, DWORD)\n{\n    ScheduleFrame(hwnd);\n}\n<\/pre>\n<p>\nTo schedule the painting of a new frame,\nwe invalidate our window and\ncancel any outstanding animation timer\n(because the timer is no longer needed\nnow that a paint has been scheduled).\n<\/p>\n<pre>\nvoid OnWindowPosChanged(HWND hwnd, LPWINDOWPOS lpwpos)\n{\n    if (IsWindowVisible(hwnd)) {\n        POINT ptRest = CalcRestPoint(hwnd);\n        if (ptRest.x != g_ptRest.x ||\n            ptRest.y != g_ptRest.y) {\n          g_mX.ShiftOrigin(g_ptRest.x - ptRest.x);\n          g_mY.ShiftOrigin(g_ptRest.y - ptRest.y);\n          ScheduleFrame(hwnd);\n        }\n        g_ptRest = ptRest;\n    }\n}\n    HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGED, OnWindowPosChanged);\n<\/pre>\n<p>\nIf the window changes its rest point while it is vislble,\nthen move the origin of the motion variables and schedule\na new frame of animation.\n<\/p>\n<p>\nOkay, here&#8217;s the fun part: Drawing the moving circle.\n<\/p>\n<pre>\nvoid\nPaintContent(HWND hwnd, PAINTSTRUCT *pps)\n{\n RECT rc;\n g_mX.Tick();\n g_mY.Tick();\n POINT ptOrigin = { 0, 0 };\n ClientToScreen(hwnd, &amp;ptOrigin);\n POINT ptOrg;\n SetWindowOrgEx(pps-&gt;hdc, ptOrigin.x, ptOrigin.y, &amp;ptOrg);\n int x = g_ptRest.x + static_cast&lt;int&gt;(floor(g_mX.Pos() + 0.5f));\n int y = g_ptRest.y + static_cast&lt;int&gt;(floor(g_mY.Pos() + 0.5f));\n Ellipse(pps-&gt;hdc, x - 20, y - 20, x + 20, y + 20);\n SetWindowOrgEx(pps-&gt;hdc, ptOrg.x, ptOrg.y, nullptr);\n if (g_mX.Moving() || g_mY.Moving()) {\n  SetTimer(hwnd, 1, 30, InvalidateMe);\n }\n}\n<\/pre>\n<p>\nWe tick the motion variables to get their current locations,\nthen\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/06\/24\/10428001.aspx\">\ntinker with our window origin because we&#8217;re going to be drawing\nbased on screen coordinates<\/a>.\nWe then draw a circle at the current animated position,\nand if the circle is still moving, we schedule a timer to draw\nthe next frame.\n<\/p>\n<p>\nFinally, we initialize our rest point before we show the window,\nso that the circle starts out at rest.\n<\/p>\n<pre>\n        <font COLOR=\"blue\">g_ptRest = CalcRestPoint(hwnd);<\/font>\n        ShowWindow(hwnd, nShowCmd);\n<\/pre>\n<p>\nAnd that&#8217;s it.\nRun the program and move it around.\nThe circle will seek the center of the window,\nwherever it is.\n<\/p>\n<p>\n(For extra credit, you can also add\n<\/p>\n<pre>\nUINT OnNCHitTest(HWND hwnd, int x, int y)\n{\n    UINT ht = FORWARD_WM_NCHITTEST(hwnd, x, y, DefWindowProc);\n    if (ht == HTCLIENT) ht = HTCAPTION;\n    return ht;\n}\n    HANDLE_MSG(hwnd, WM_NCHITTEST, OnNCHitTest);\n<\/pre>\n<p>\nso that\n<a HREF=\"http:\/\/support.microsoft.com\/kb\/320687\">\nthe window can be dragged by its client area<\/a>.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today&#8217;s Little Program uses the technique we saw last week of drawing content at a fixed screen position, regardless of window position, but adds a little physics to it. Start with our scratch program and make these changes: #include &lt;math.h&gt; \/\/ physics requires math (go figure) #define Omega 2.0f class Motion { public: Motion() : [&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-3943","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Today&#8217;s Little Program uses the technique we saw last week of drawing content at a fixed screen position, regardless of window position, but adds a little physics to it. Start with our scratch program and make these changes: #include &lt;math.h&gt; \/\/ physics requires math (go figure) #define Omega 2.0f class Motion { public: Motion() : [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/3943","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=3943"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/3943\/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=3943"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=3943"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=3943"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}