home *** CD-ROM | disk | FTP | other *** search
/ Beginning Direct3D Game Programming / Direct3D.iso / directx / dxf / samples / multimedia / directinput / diconfig / flexwnd.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-22  |  13.2 KB  |  609 lines

  1. //-----------------------------------------------------------------------------
  2. // File: flexwnd.cpp
  3. //
  4. // Desc: CFlexWnd is a generic class that encapsulates the functionalities
  5. //       of a window.  All other window classes are derived from CFlexWnd.
  6. //
  7. //       Child classes can have different behavior by overriding the
  8. //       overridable message handlers (OnXXX members).
  9. //
  10. // Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  11. //-----------------------------------------------------------------------------
  12.  
  13. #include "common.hpp"
  14. #include "typeinfo.h"
  15.  
  16. BOOL CFlexWnd::sm_bWndClassRegistered = FALSE;
  17. WNDCLASSEX CFlexWnd::sm_WndClass;
  18. LPCTSTR CFlexWnd::sm_tszWndClassName = _T("Microsoft.CFlexWnd.WndClassName");
  19. HINSTANCE CFlexWnd::sm_hInstance = NULL;
  20. CFlexToolTip CFlexWnd::s_ToolTip;  // Shared tooltip window object
  21. DWORD CFlexWnd::s_dwLastMouseMove;  // Last GetTickCount() that we have a WM_MOUSEMOVE
  22. HWND CFlexWnd::s_hWndLastMouseMove;  // Last window handle of WM_MOUSEMOVE
  23. LPARAM CFlexWnd::s_PointLastMouseMove;  // Last point of WM_MOUSEMOVE
  24.  
  25.  
  26. int NewID()
  27. {
  28.     static int i = 0;
  29.     return ++i;
  30. }
  31.  
  32. CFlexWnd::CFlexWnd() : m_nID(NewID()),
  33.     m_hWnd(m_privhWnd), m_privhWnd(NULL), m_hRenderInto(NULL),
  34.     m_bIsDialog(FALSE),    m_bRender(FALSE),
  35.     m_bReadOnly(FALSE)
  36. {
  37. }
  38.  
  39. CFlexWnd::~CFlexWnd()
  40. {
  41.     Destroy();
  42. }
  43.  
  44. void CFlexWnd::Destroy()
  45. {
  46.     if (m_hWnd != NULL)
  47.         DestroyWindow(m_hWnd);
  48.  
  49.     assert(m_privhWnd == NULL);
  50. }
  51.  
  52. BOOL CFlexWnd::IsDialog()
  53. {
  54.     return HasWnd() && m_bIsDialog;
  55. }
  56.  
  57. void CFlexWnd::OnRender(BOOL bInternalCall)
  58. {
  59.     // if parent is flexwnd and both are in render mode, pass to parent
  60.     if (!m_hWnd)
  61.         return;
  62.     HWND hParent = GetParent(m_hWnd);
  63.     if (!hParent)
  64.         return;
  65.     CFlexWnd *pParent = GetFlexWnd(hParent);
  66.     if (!pParent)
  67.         return;
  68.     if (pParent->InRenderMode() && InRenderMode())
  69.         pParent->OnRender(TRUE);
  70. }
  71.  
  72. BOOL CFlexWnd::OnEraseBkgnd(HDC hDC)
  73. {
  74.     if (InRenderMode())
  75.         return TRUE;
  76.  
  77. /*    if (IsDialog())
  78.         return FALSE;*/
  79.  
  80.     return TRUE;
  81. }
  82.  
  83. struct GETFLEXWNDSTRUCT {
  84.     int cbSize;
  85.     BOOL bFlexWnd;
  86.     CFlexWnd *pFlexWnd;
  87. };
  88.  
  89. // This function takes a HWND and returns a pointer to CFlexWnd if the HWND is a window
  90. // created by the UI.
  91. CFlexWnd *CFlexWnd::GetFlexWnd(HWND hWnd)
  92. {
  93.     if (hWnd == NULL)
  94.         return NULL;
  95.  
  96.     GETFLEXWNDSTRUCT gfws;
  97.     gfws.cbSize = sizeof(gfws);
  98.     gfws.bFlexWnd = FALSE;
  99.     gfws.pFlexWnd = NULL;
  100.     SendMessage(hWnd, WM_GETFLEXWND, 0, (LPARAM)(LPVOID)(FAR GETFLEXWNDSTRUCT *)&gfws);
  101.  
  102.     if (gfws.bFlexWnd)
  103.         return gfws.pFlexWnd;
  104.     else
  105.         return NULL;
  106. }
  107.  
  108. // Basic window proc. It simply forward interesting messages to the appropriate handlers (OnXXX).
  109. // If child class defines this function, it should pass unhandled messages to CFlexWnd.
  110. LRESULT CFlexWnd::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  111. {
  112.     switch (msg)
  113.     {
  114.         case WM_GETFLEXWND:
  115.         {
  116.             if ((LPVOID)lParam == NULL)
  117.                 break;
  118.  
  119.             GETFLEXWNDSTRUCT &gfws = *((FAR GETFLEXWNDSTRUCT *)(LPVOID)lParam);
  120.  
  121.             switch (gfws.cbSize)
  122.             {
  123.                 case sizeof(GETFLEXWNDSTRUCT):
  124.                     gfws.bFlexWnd = TRUE;
  125.                     gfws.pFlexWnd = this;
  126.                     return 0;
  127.  
  128.                 default:
  129.                     assert(0);
  130.                     break;
  131.             }
  132.             break;
  133.         }
  134.  
  135.         case WM_CREATE:
  136.         {
  137.             LPCREATESTRUCT lpCreateStruct = (LPCREATESTRUCT)lParam;
  138.             
  139.             LRESULT lr = OnCreate(lpCreateStruct);
  140.             
  141.             if (lr != -1)
  142.                 OnInit();
  143.  
  144.             return lr;
  145.         }
  146.  
  147.         case WM_INITDIALOG:
  148.         {
  149.             BOOL b = OnInitDialog();
  150.             OnInit();
  151.             return b;
  152.         }
  153.  
  154.         case WM_TIMER:
  155.             OnTimer((UINT)wParam);
  156.             return 0;
  157.  
  158.         case WM_ERASEBKGND:
  159.             return OnEraseBkgnd((HDC)wParam);
  160.  
  161.         case WM_PAINT:
  162.         {
  163.             // Check the update rectangle.  If we don't have it, exit immediately.
  164.             if (typeid(*this) == typeid(CDeviceView) && !GetUpdateRect(m_hWnd, NULL, FALSE))
  165.                 return 0;
  166.             PAINTSTRUCT ps;
  167.             HDC    hDC = BeginPaint(hWnd, &ps);
  168.             if (InRenderMode())
  169.                 OnRender(TRUE);
  170.             else
  171.                 DoOnPaint(hDC);
  172.             EndPaint(hWnd, &ps);
  173.             return 0;
  174.         }
  175.  
  176.         case WM_COMMAND:
  177.         {
  178.             WORD wNotifyCode = HIWORD(wParam);
  179.             WORD wID = LOWORD(wParam);
  180.             HWND hWnd = (HWND)lParam;
  181.             return OnCommand(wNotifyCode, wID, hWnd);
  182.         }
  183.  
  184.         case WM_NOTIFY:    
  185.             return OnNotify(wParam, lParam);
  186.  
  187.         case WM_MOUSEMOVE:
  188.         case WM_LBUTTONDOWN:
  189.         case WM_RBUTTONDOWN:
  190.         case WM_LBUTTONDBLCLK:
  191.         {
  192.             POINT point = {int(LOWORD(lParam)), int(HIWORD(lParam))};
  193.             switch (msg)
  194.             {
  195.                 case WM_MOUSEMOVE: OnMouseOver(point, wParam); break;
  196.                 case WM_LBUTTONDOWN: OnClick(point, wParam, TRUE); break;
  197.                 case WM_RBUTTONDOWN: OnClick(point, wParam, FALSE); break;
  198.                 case WM_LBUTTONDBLCLK: OnDoubleClick(point, wParam, TRUE); break;
  199.             }
  200.             return 0;
  201.         }
  202.  
  203.         case WM_DESTROY:
  204.             OnDestroy();
  205.             m_privhWnd = NULL;
  206.             return 0;
  207.     }
  208.  
  209.     if (!m_bIsDialog)
  210.         return DefWindowProc(hWnd, msg, wParam, lParam);
  211.     else
  212.         return 0;
  213. }
  214. static HMENU windex = 0;
  215.  
  216. BOOL CFlexWnd::EndDialog(int n)
  217. {
  218.     if (!m_bIsDialog || m_hWnd == NULL)
  219.     {
  220.         assert(0);
  221.         return FALSE;
  222.     }
  223.  
  224.     return ::EndDialog(m_hWnd, n);
  225. }
  226.  
  227. int CFlexWnd::DoModal(HWND hParent, int nTemplate, HINSTANCE hInst)
  228. {
  229.     return DoModal(hParent, MAKEINTRESOURCE(nTemplate), hInst);
  230. }
  231.  
  232. HWND CFlexWnd::DoModeless(HWND hParent, int nTemplate, HINSTANCE hInst)
  233. {
  234.     return DoModeless(hParent, MAKEINTRESOURCE(nTemplate), hInst);
  235. }
  236.  
  237. int CFlexWnd::DoModal(HWND hParent, LPCTSTR lpTemplate, HINSTANCE hInst)
  238. {
  239.     if (m_hWnd != NULL)
  240.     {
  241.         assert(0);
  242.         return -1;
  243.     }
  244.  
  245.     if (hInst == NULL)
  246.         hInst = CFlexWnd::sm_hInstance;
  247.  
  248.     return (int)DialogBoxParam(hInst, lpTemplate, hParent,
  249.         (DLGPROC)__BaseFlexWndDialogProc, (LPARAM)(void *)this);
  250. }
  251.  
  252. HWND CFlexWnd::DoModeless(HWND hParent, LPCTSTR lpTemplate, HINSTANCE hInst)
  253. {
  254.     if (m_hWnd != NULL)
  255.     {
  256.         assert(0);
  257.         return NULL;
  258.     }
  259.  
  260.     if (hInst == NULL)
  261.         hInst = CFlexWnd::sm_hInstance;
  262.  
  263.     return CreateDialogParam(hInst, lpTemplate, hParent,
  264.         (DLGPROC)__BaseFlexWndDialogProc, (LPARAM)(void *)this);
  265. }
  266.  
  267. HWND CFlexWnd::Create(HWND hParent, const RECT &rect, BOOL bVisible)
  268. {
  269.     ++(*(LPBYTE*)&windex);
  270.     return Create(hParent, _T("(unnamed)"), 0,
  271.         WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_EX_NOPARENTNOTIFY | (bVisible ? WS_VISIBLE : 0),
  272.         rect, windex);
  273. }
  274.  
  275. HWND CFlexWnd::Create(HWND hParent, LPCTSTR tszName, DWORD dwExStyle, DWORD dwStyle, const RECT &rect, HMENU hMenu)
  276. {
  277.     HWND hWnd = NULL;
  278.  
  279.     if (m_hWnd != NULL)
  280.     {
  281.         assert(0);
  282.         return hWnd;
  283.     }
  284.  
  285.     if (hMenu == NULL && (dwStyle & WS_CHILD))
  286.     {
  287.         ++(*(LPBYTE*)&windex);
  288.         hMenu = windex;
  289.     }
  290.  
  291.     hWnd = CreateWindowEx(
  292.         dwExStyle,
  293.         CFlexWnd::sm_tszWndClassName,
  294.         tszName,
  295.         dwStyle,
  296.         rect.left, rect.top,
  297.         rect.right - rect.left, rect.bottom - rect.top,
  298.         hParent,
  299.         hMenu,
  300.         CFlexWnd::sm_hInstance,
  301.         (void *)this);
  302.  
  303.     DWORD dwe;
  304.     if (!hWnd)
  305.         dwe = GetLastError();
  306.  
  307.     assert(m_hWnd == hWnd);
  308.  
  309.     return hWnd;
  310. }
  311.  
  312. void CFlexWnd::SetHWND(HWND hWnd)
  313. {
  314.     assert(m_hWnd == NULL && hWnd != NULL);
  315.     m_privhWnd = hWnd;
  316.     assert(m_hWnd == m_privhWnd);
  317.  
  318.     InitFlexWnd();
  319. }
  320.  
  321. void CFlexWnd::InitFlexWnd()
  322. {
  323.     if (!HasWnd())
  324.         return;
  325.  
  326.     HWND hParent = GetParent(m_hWnd);
  327.     CFlexWnd *pParent = GetFlexWnd(hParent);
  328.     if (pParent && pParent->InRenderMode())
  329.         SetRenderMode();
  330. }
  331.  
  332. TCHAR sg_tszFlexWndPointerProp[] = _T("CFlexWnd *");
  333.  
  334. LRESULT CALLBACK __BaseFlexWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  335. {
  336.     CFlexWnd *pThis = (CFlexWnd *)GetProp(hWnd, sg_tszFlexWndPointerProp);
  337.  
  338.     if (msg == WM_MOUSEMOVE)
  339.     {
  340.         // Filter out the message with same window handle and point.
  341.         // Windows sometimes seems to send us WM_MOUSEMOVE message even though the mouse is not moved.
  342.         if (CFlexWnd::s_hWndLastMouseMove != hWnd || CFlexWnd::s_PointLastMouseMove != lParam)
  343.         {
  344.             CFlexWnd::s_hWndLastMouseMove = hWnd;
  345.             CFlexWnd::s_PointLastMouseMove = lParam;
  346.             CFlexWnd::s_dwLastMouseMove = GetTickCount();  // Get timestamp
  347.             CFlexWnd::s_ToolTip.SetEnable(FALSE);
  348.             CFlexWnd::s_ToolTip.SetToolTipParent(NULL);
  349.         }
  350.     }
  351.  
  352.     switch (msg)
  353.     {
  354.         case WM_CREATE:
  355.         {
  356.             LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
  357.             if (lpcs == NULL)
  358.                 break;
  359.  
  360.             pThis = (CFlexWnd *)(void *)(lpcs->lpCreateParams);
  361.             assert(sizeof(HANDLE) == sizeof(CFlexWnd *));
  362.             SetProp(hWnd, sg_tszFlexWndPointerProp, (HANDLE)pThis);
  363.  
  364.             if (pThis != NULL)
  365.             {
  366.                 pThis->m_bIsDialog = FALSE;
  367.                 pThis->SetHWND(hWnd);
  368.             }
  369.             break;
  370.         }
  371.     }
  372.  
  373.     if (pThis != NULL)
  374.         return pThis->WndProc(hWnd, msg, wParam, lParam);
  375.     else
  376.         return DefWindowProc(hWnd, msg, wParam, lParam);
  377. }
  378.  
  379. LRESULT CALLBACK __BaseFlexWndDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  380. {
  381.     CFlexWnd *pThis = (CFlexWnd *)GetProp(hWnd, sg_tszFlexWndPointerProp);
  382.  
  383.     switch (msg)
  384.     {
  385.         case WM_INITDIALOG:
  386.             pThis = (CFlexWnd *)(void *)lParam;
  387.             assert(sizeof(HANDLE) == sizeof(CFlexWnd *));
  388.             SetProp(hWnd, sg_tszFlexWndPointerProp, (HANDLE)pThis);
  389.             if (pThis != NULL)
  390.             {
  391.                 pThis->m_bIsDialog = TRUE;
  392.                 pThis->SetHWND(hWnd);
  393.             }
  394.             break;
  395.     }
  396.     
  397.     if (pThis != NULL)
  398.         return (BOOL)pThis->WndProc(hWnd, msg, wParam, lParam);
  399.     else
  400.         return FALSE;
  401. }
  402.  
  403. void CFlexWnd::Invalidate()
  404. {
  405.     if (m_hWnd != NULL)
  406.         InvalidateRect(m_hWnd, NULL, TRUE);
  407. }
  408.  
  409. SIZE CFlexWnd::GetClientSize() const
  410. {
  411.     RECT rect = {0, 0, 0, 0};
  412.     if (m_hWnd != NULL)
  413.         ::GetClientRect(m_hWnd, &rect);
  414.     SIZE size = {
  415.         rect.right - rect.left,
  416.         rect.bottom - rect.top};
  417.     return size;
  418. }
  419.  
  420. void CFlexWnd::FillWndClass(HINSTANCE hInst)
  421. {
  422.     sm_WndClass.cbSize = sizeof(WNDCLASSEX);
  423.     sm_WndClass.style = CS_DBLCLKS;
  424.     sm_WndClass.lpfnWndProc = __BaseFlexWndProc;
  425.     sm_WndClass.cbClsExtra = 0;
  426.     sm_WndClass.cbWndExtra = sizeof(CFlexWnd *);
  427.     sm_WndClass.hInstance = sm_hInstance = hInst;
  428.     sm_WndClass.hIcon = NULL;
  429.     sm_WndClass.hCursor = NULL;
  430.     sm_WndClass.hbrBackground = NULL;
  431.     sm_WndClass.lpszMenuName = NULL;
  432.     sm_WndClass.lpszClassName = sm_tszWndClassName;
  433.     sm_WndClass.hIconSm = NULL;
  434. }
  435.  
  436. void CFlexWnd::RegisterWndClass(HINSTANCE hInst)
  437. {
  438.     if (hInst == NULL)
  439.     {
  440.         assert(0);
  441.         return;
  442.     }
  443.  
  444.     FillWndClass(hInst);
  445.     RegisterClassEx(&sm_WndClass);
  446.     sm_bWndClassRegistered = TRUE;
  447. }
  448.  
  449. void CFlexWnd::UnregisterWndClass(HINSTANCE hInst)
  450. {
  451.     if (hInst == NULL)
  452.         return;
  453.  
  454.     UnregisterClass(sm_tszWndClassName, hInst);
  455.     sm_bWndClassRegistered = FALSE;
  456. }
  457.  
  458. void CFlexWnd::GetClientRect(LPRECT lprect) const
  459. {
  460.     if (lprect == NULL || m_hWnd == NULL)
  461.         return;
  462.  
  463.     ::GetClientRect(m_hWnd, lprect);
  464. }
  465.  
  466. LPCTSTR CFlexWnd::GetDefaultClassName()
  467. {
  468.     return CFlexWnd::sm_tszWndClassName;
  469. }
  470.  
  471. void CFlexWnd::SetRenderMode(BOOL bRender)
  472. {
  473.     if (bRender == m_bRender)
  474.         return;
  475.  
  476.     m_bRender = bRender;
  477.     Invalidate();
  478. }
  479.  
  480. BOOL CFlexWnd::InRenderMode()
  481. {
  482.     return m_bRender;
  483. }
  484.  
  485. void EnumChildWindowsZDown(HWND hParent, WNDENUMPROC proc, LPARAM lParam)
  486. {
  487.     if (hParent == NULL || proc == NULL)
  488.         return;
  489.  
  490.     HWND hWnd = GetWindow(hParent, GW_CHILD);
  491.  
  492.     while (hWnd != NULL)
  493.     {
  494.         if (!proc(hWnd, lParam))
  495.             break;
  496.  
  497.         hWnd = GetWindow(hWnd, GW_HWNDNEXT);
  498.     }
  499. }
  500.  
  501. void EnumSiblingsAbove(HWND hParent, WNDENUMPROC proc, LPARAM lParam)
  502. {
  503.     if (hParent == NULL || proc == NULL)
  504.         return;
  505.  
  506.     HWND hWnd = hParent;
  507.  
  508.     while (1)
  509.     {
  510.         hWnd = GetWindow(hWnd, GW_HWNDPREV);
  511.  
  512.         if (hWnd == NULL)
  513.             break;
  514.  
  515.         if (!proc(hWnd, lParam))
  516.             break;
  517.     }
  518. }
  519.  
  520. static BOOL CALLBACK RenderIntoClipChild(HWND hWnd, LPARAM lParam)
  521. {
  522.     CFlexWnd *pThis = (CFlexWnd *)(LPVOID)lParam;
  523.     return pThis->RenderIntoClipChild(hWnd);
  524. }
  525.  
  526. static BOOL CALLBACK RenderIntoRenderChild(HWND hWnd, LPARAM lParam)
  527. {
  528.     CFlexWnd *pThis = (CFlexWnd *)(LPVOID)lParam;
  529.     // Check if this is the immediate child. Do nothing if it's not immediate.
  530.     HWND hParent = GetParent(hWnd);
  531.     if (hParent != pThis->m_hWnd)
  532.         return TRUE;
  533.     return pThis->RenderIntoRenderChild(hWnd);
  534. }
  535.  
  536. BOOL CFlexWnd::RenderIntoClipChild(HWND hChild)
  537. {
  538.     if (m_hRenderInto != NULL && HasWnd() && hChild && IsWindowVisible(hChild))
  539.     {
  540.         RECT rect;
  541.         GetWindowRect(hChild, &rect);
  542.         POINT ul = {rect.left, rect.top}, lr = {rect.right, rect.bottom};
  543.         ScreenToClient(m_hWnd, &ul);
  544.         ScreenToClient(m_hWnd, &lr);
  545.         ExcludeClipRect(m_hRenderInto, ul.x, ul.y, lr.x, lr.y);
  546.     }
  547.     return TRUE;
  548. }
  549.  
  550. BOOL CFlexWnd::RenderIntoRenderChild(HWND hChild)
  551. {
  552.     CFlexWnd *pChild = GetFlexWnd(hChild);
  553.     if (m_hRenderInto != NULL && HasWnd() && pChild != NULL && IsWindowVisible(hChild))
  554.     {
  555.         RECT rect;
  556.         GetWindowRect(hChild, &rect);
  557.         POINT ul = {rect.left, rect.top};
  558.         ScreenToClient(m_hWnd, &ul);
  559.         pChild->RenderInto(m_hRenderInto, ul.x, ul.y);
  560.     }
  561.     return TRUE;
  562. }
  563.  
  564. void CFlexWnd::RenderInto(HDC hDC, int x, int y)
  565. {
  566.     if (hDC == NULL)
  567.         return;
  568.         
  569.     int sdc = SaveDC(hDC);
  570.     {
  571.         OffsetViewportOrgEx(hDC, x, y, NULL);
  572.         SIZE size = GetClientSize();
  573.         IntersectClipRect(hDC, 0, 0, size.cx, size.cy);
  574.  
  575.         m_hRenderInto = hDC;
  576.  
  577.         int sdc2 = SaveDC(hDC);
  578.         {
  579.             EnumChildWindows/*ZDown*/(m_hWnd, ::RenderIntoClipChild, (LPARAM)(PVOID)this);
  580.             EnumSiblingsAbove(m_hWnd, ::RenderIntoClipChild, (LPARAM)(PVOID)this);
  581.             DoOnPaint(hDC);
  582.         }
  583.         if (sdc2)
  584.             RestoreDC(hDC, sdc2);
  585.  
  586.         EnumChildWindows/*ZDown*/(m_hWnd, ::RenderIntoRenderChild, (LPARAM)(PVOID)this);
  587.  
  588.         m_hRenderInto = NULL;
  589.     }
  590.  
  591.     if (sdc)
  592.         RestoreDC(hDC, sdc);
  593. }
  594.  
  595. void CFlexWnd::SetCapture()
  596. {
  597.     ::SetCapture(m_hWnd);
  598. }
  599.  
  600. void CFlexWnd::ReleaseCapture()
  601. {
  602.     ::ReleaseCapture();
  603. }
  604.  
  605. void CFlexWnd::DoOnPaint(HDC hDC)
  606. {
  607.     OnPaint(hDC);
  608. }
  609.