home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectInput / DIConfig / populate.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  14.3 KB  |  528 lines

  1. //-----------------------------------------------------------------------------
  2. // File: populate.cpp
  3. //
  4. // Desc: This file contains the population functions.  These are all
  5. //       accessed through PopulateAppropriately().  That function creates
  6. //       views & controls based on the type of the device that the passed
  7. //       DeviceUI represents.
  8. //
  9. // Copyright (C) 1999-2001 Microsoft Corporation. All Rights Reserved.
  10. //-----------------------------------------------------------------------------
  11.  
  12. #include "common.hpp"
  13.  
  14.  
  15. // these functions are internal to this filed, called only by
  16. // PopulateAppropriately().
  17. HRESULT PopulateViaGetImageInfo(CDeviceUI &ui);
  18. HRESULT PopulateFromImageInfoHeader(CDeviceUI &ui, const DIDEVICEIMAGEINFOHEADERW &);
  19. HRESULT PopulateListView(CDeviceUI &ui);
  20. HRESULT PopulateErrorView(CDeviceUI &ui);
  21.  
  22.  
  23. // Clears the entire passed DeviceUI, then fills it with views and
  24. // controls based on device type.  Tries to gaurantee that there will
  25. // be at least one view.
  26. HRESULT PopulateAppropriately(CDeviceUI &ui)
  27. {
  28.     HRESULT hr = S_OK;
  29.  
  30.     // first empty the ui
  31.     ui.Unpopulate();
  32.  
  33.     // get device type
  34.     DWORD dwdt = ui.m_didi.dwDevType;
  35.     DWORD dwType = (DWORD)(LOBYTE(LOWORD(dwdt)));
  36.     DWORD dwSubType = (DWORD)(HIBYTE(LOWORD(dwdt)));
  37.  
  38.     // based on type...
  39.     switch (dwType)
  40.     {
  41.         default:
  42.             // unless its a type we don't ever want views for,
  43.             // populate via the GetImageInfo() API
  44.             hr = PopulateViaGetImageInfo(ui);
  45.             if (SUCCEEDED(hr) && ui.GetNumViews() > 0)
  46.                 return hr;
  47.  
  48.             // if it failed or resulted in nothing,
  49.             // clear anything that might've been added
  50.             ui.Unpopulate();
  51.  
  52.             // intentional fallthrough
  53.  
  54.         case DI8DEVTYPE_MOUSE:
  55.         case DI8DEVTYPE_KEYBOARD:
  56.             // for types that we don't ever want views for
  57.             // we populate the list view without trying the above
  58.             hr = PopulateListView(ui);
  59.             
  60.             // if we still failed or don't have any views,
  61.             // populate with error message view
  62.             if (FAILED(hr) || ui.GetNumViews() < 1)
  63.             {
  64.                 // empty
  65.                 ui.Unpopulate();
  66.  
  67.                 // show error message
  68.                 hr = PopulateErrorView(ui);
  69.             }
  70.  
  71.             // this function should guarantee success
  72.             assert(!FAILED(hr));
  73.  
  74.             return hr;
  75.     }
  76. }
  77.  
  78. // Calls the GetImageInfo() API to get the view images and controls
  79. // for the entire device, and returns a failure if there's the
  80. // slightest problem (if GII() fails, or if an image fails to load,
  81. // etc.)
  82. HRESULT PopulateViaGetImageInfo(CDeviceUI &ui)
  83. {
  84.     if (!ui.m_lpDID)
  85.         return E_FAIL;
  86.  
  87.     HRESULT hr = S_OK;
  88.  
  89.     DIDEVICEIMAGEINFOHEADERW m_diImgInfoHdr;
  90.     LPDIDEVICEIMAGEINFOW &lprgdiImgData = m_diImgInfoHdr.lprgImageInfoArray;
  91.  
  92.     ZeroMemory( &m_diImgInfoHdr, sizeof(DIDEVICEIMAGEINFOHEADERW) );
  93.     m_diImgInfoHdr.dwSize = sizeof(DIDEVICEIMAGEINFOHEADERW);
  94.     m_diImgInfoHdr.dwSizeImageInfo = sizeof(DIDEVICEIMAGEINFOW);
  95.  
  96.     // Retrieve the required buffer size.
  97.     hr = ui.m_lpDID->GetImageInfo( &m_diImgInfoHdr );
  98.     if (FAILED(hr))
  99.     {
  100.         etrace1(_T("GetImageInfo() failed while trying to get required buffer size.  hr = 0x%08x\n"), hr);
  101.         return E_FAIL;
  102.     }
  103.  
  104.     // Allocate the buffer.
  105.     lprgdiImgData = (LPDIDEVICEIMAGEINFOW) malloc( (size_t)
  106.         (m_diImgInfoHdr.dwBufferSize = m_diImgInfoHdr.dwBufferUsed) );
  107.     if (lprgdiImgData == NULL)
  108.     {
  109.         etrace1(_T("Could not allocate buffer of size %d.\n"), m_diImgInfoHdr.dwBufferSize);
  110.         return E_FAIL;
  111.     }
  112.  
  113.     trace(_T("Allocated buffer.\n"));
  114.     traceDWORD(m_diImgInfoHdr.dwBufferSize);
  115.  
  116.     m_diImgInfoHdr.lprgImageInfoArray = lprgdiImgData;
  117.  
  118.     // Get the display info.
  119.     hr = ui.m_lpDID->GetImageInfo( &m_diImgInfoHdr );
  120.     if (FAILED(hr))
  121.     {
  122.         etrace1(_T("GetImageInfo() failed trying to get image info.  hr = 0x%08x\n"), hr);
  123.         free(lprgdiImgData);
  124.         lprgdiImgData = NULL;
  125.         return E_FAIL;
  126.     }
  127.  
  128.     // actually populate now
  129.     traceDWORD(m_diImgInfoHdr.dwBufferUsed);
  130.     hr = PopulateFromImageInfoHeader(ui, m_diImgInfoHdr);
  131.     if (FAILED(hr))
  132.         return hr;
  133.  
  134.     // free stuff
  135.     free(lprgdiImgData);
  136.     lprgdiImgData = NULL;
  137.  
  138.     return S_OK;
  139. }
  140.  
  141. // basically does the work for the above function after the header
  142. // is actually retrieved
  143. HRESULT PopulateFromImageInfoHeader(CDeviceUI &ui, const DIDEVICEIMAGEINFOHEADERW &dih)
  144. {
  145.     tracescope(ts1, _T("CGetImageInfoPopHelper::Init()...\n"));
  146.  
  147.     traceDWORD(dih.dwSizeImageInfo);
  148.     traceDWORD(dih.dwBufferSize);
  149.     traceDWORD(dih.dwBufferUsed);
  150.  
  151.     if (dih.dwSizeImageInfo != sizeof(DIDEVICEIMAGEINFOW))
  152.     {
  153.         etrace(_T("dwSizeImageInfo Incorrect.\n"));
  154.         assert(0);
  155.         return E_FAIL;
  156.     }
  157.     DWORD dwNumElements = dih.dwBufferUsed / dih.dwSizeImageInfo;
  158.     if (dwNumElements * dih.dwSizeImageInfo != dih.dwBufferUsed
  159.         || dih.dwBufferUsed < dih.dwBufferSize)
  160.     {
  161.         etrace(_T("Could not confidently calculate dwNumElements.\n"));
  162.         assert(0);
  163.         return E_FAIL;
  164.     }
  165.  
  166.     DWORD i;
  167.  
  168.     traceDWORD(dwNumElements);
  169.  
  170.     bidirlookup<DWORD, int> offset_view;
  171.  
  172.     {
  173.         tracescope(ts2, _T("First Pass...\n"));
  174.  
  175.         for (i = 0; i < dwNumElements; i++)
  176.             if (dih.lprgImageInfoArray[i].dwFlags & DIDIFT_CONFIGURATION)
  177.             {
  178.                 LPDIDEVICEIMAGEINFOW lpInfoBase = dih.lprgImageInfoArray;
  179.                 DWORD index = i;
  180.                 {
  181.                     tracescope(ts1, _T("AddViewInfo()...\n"));
  182.                     traceHEXPTR(lpInfoBase);
  183.                     traceDWORD(index);
  184.  
  185.                     if (lpInfoBase == NULL)
  186.                     {
  187.                         etrace(_T("lpInfoBase NULL\n"));
  188.                         return E_FAIL;
  189.                     }
  190.  
  191.                     DIDEVICEIMAGEINFOW &info = lpInfoBase[index];
  192.                     DWORD dwOffset = index;
  193.  
  194.                     // add view info to array
  195.                     CDeviceView *pView = ui.NewView();
  196.                     if (!pView)
  197.                     {
  198.                         etrace(_T("Could not create new view.\n"));
  199.                         return E_FAIL;
  200.                     }
  201.                     int nView = pView->GetViewIndex();
  202.  
  203.                     tracescope(ts2, _T("Adding View "));
  204.                     trace2(_T("%d (info index %u)\n"), nView, index);
  205.  
  206.                     // set view's imagepath
  207.                     if (!info.tszImagePath)
  208.                     {
  209.                         etrace(_T("No image path.\n"));
  210.                         return E_FAIL;
  211.                     }
  212.                     LPTSTR tszImagePath = AllocLPTSTR(info.tszImagePath);
  213.                     if (!tszImagePath)
  214.                     {
  215.                         etrace(_T("Could not copy image path.\n"));
  216.                         return E_FAIL;
  217.                     }
  218.  
  219.                     // set the view's image path
  220.                     pView->SetImagePath(tszImagePath);
  221.  
  222.                     // create bitmap from path
  223.                     LPDIRECT3DSURFACE8 lpSurf3D = ui.m_uig.GetSurface3D();
  224.                     CBitmap *pbm = CBitmap::CreateViaD3DX(tszImagePath, lpSurf3D);
  225.                     traceSTR(info.tszImagePath);
  226.                     traceHEXPTR(pbm);
  227.                     traceDWORD(dwOffset);
  228.                     free(tszImagePath);
  229.                     tszImagePath = NULL;
  230.                     if (lpSurf3D)
  231.                     {
  232.                         lpSurf3D->Release();  // Need to free the surface instance after we are done as AddRef() was called earlier.
  233.                         lpSurf3D = NULL;
  234.                     }
  235.                     if (!pbm)
  236.                     {
  237.                         etrace(_T("Could not create image from path.\n"));
  238.                         return E_FAIL;
  239.                     }
  240.  
  241.                     // set the view's image
  242.                     assert(pbm != NULL);
  243.                     pView->SetImage(pbm);    // setimage steals the bitmap pointer
  244.                     assert(pbm == NULL);
  245.  
  246.                     // add conversion from offset to view
  247.                     offset_view.add(dwOffset, nView);
  248.                 }
  249.             }
  250.     }
  251.  
  252.     {
  253.         tracescope(ts2, _T("Second Pass...\n"));
  254.  
  255.         for (i = 0; i < dwNumElements; i++)
  256.         {
  257.             DWORD dwFlags = dih.lprgImageInfoArray[i].dwFlags;
  258.  
  259.             if (dwFlags & DIDIFT_OVERLAY)
  260.             {
  261.                 LPDIDEVICEIMAGEINFOW lpInfoBase = dih.lprgImageInfoArray;
  262.                 DWORD index = i;
  263.                 {
  264.                     tracescope(ts1, _T("AddControlInfo()...\n"));
  265.                     traceHEXPTR(lpInfoBase);
  266.                     traceDWORD(index);
  267.  
  268.                     if (lpInfoBase == NULL)
  269.                     {
  270.                         etrace(_T("lpInfoBase NULL\n"));
  271.                         return E_FAIL;
  272.                     }
  273.  
  274.                     DIDEVICEIMAGEINFOW &info = lpInfoBase[index];
  275.  
  276.                     int nViewIndex = 0;
  277.                     
  278.                     if (!offset_view.getright(info.dwViewID, nViewIndex))
  279.                     {
  280.                         etrace(_T("Could not get view index\n"));
  281.                         return E_FAIL;
  282.                     }
  283.  
  284.                     if (nViewIndex < 0 || nViewIndex >= ui.GetNumViews())
  285.                     {
  286.                         etrace1(_T("Invalid view index %d\n"), nViewIndex);
  287.                         return E_FAIL;
  288.                     }
  289.  
  290.                     CDeviceView *pView = ui.GetView(nViewIndex);
  291.                     if (!pView)
  292.                     {
  293.                         etrace1(_T("\n"), nViewIndex);
  294.                         return E_FAIL;
  295.                     }
  296.  
  297.                     CDeviceControl *pControl = pView->NewControl();
  298.                     int nControl = pControl->GetControlIndex();
  299.  
  300.                     tracescope(ts2, _T("Adding Control "));
  301.                     trace4(_T("%d (info index %u) to view %d (info index %u)\n"), nControl, index, nViewIndex, info.dwViewID);
  302.  
  303.                     traceDWORD(info.dwObjID);
  304.                     traceDWORD(info.dwcValidPts);
  305.                     traceRECT(info.rcCalloutRect);
  306.                     traceRECT(info.rcOverlay);
  307.                     traceHEX(info.dwTextAlign);
  308.                     traceSTR(info.tszImagePath);
  309.  
  310.                     pControl->SetObjID(info.dwObjID);
  311.                     pControl->SetLinePoints(int(info.dwcValidPts), info.rgptCalloutLine);
  312.                     pControl->SetCalloutMaxRect(info.rcCalloutRect);
  313.                     pControl->SetAlignment(info.dwTextAlign);
  314.                     if (info.tszImagePath)
  315.                     {
  316.                         LPTSTR tszOverlayPath = AllocLPTSTR(info.tszImagePath);
  317.                         if (tszOverlayPath)
  318.                             pControl->SetOverlayPath(tszOverlayPath);
  319.                         free(tszOverlayPath);
  320.                         tszOverlayPath = NULL;
  321.                     }
  322.                     pControl->SetOverlayRect(info.rcOverlay);
  323.                     pControl->Init();
  324.                 }
  325.             }
  326.         }
  327.     }
  328.  
  329.     return S_OK;
  330. }
  331.  
  332. // Enumerates the controls on the device and creates one big list
  333. // view for the device.  Fails if it can't enumerate for some reason.
  334. HRESULT PopulateListView(CDeviceUI &ui)
  335. {
  336.     int i;
  337.     HRESULT hr = S_OK;
  338.  
  339.     // we must have the device interface
  340.     if (!ui.m_lpDID)
  341.         return E_FAIL;
  342.  
  343.     // create one view
  344.     CDeviceView *pView = ui.NewView();
  345.     if (!pView)
  346.         return E_FAIL;
  347.  
  348.     // enable scrolling on it
  349.     pView->EnableScrolling();
  350.  
  351.     // get list of controls
  352.     DIDEVOBJSTRUCT os;
  353.     hr = FillDIDeviceObjectStruct(os, ui.m_lpDID);
  354.     if (FAILED(hr))
  355.         return hr;
  356.  
  357.     // if there aren't any, fail
  358.     int n = os.nObjects;
  359.     if (n < 1)
  360.         return E_FAIL;
  361.  
  362.     // run through and create a text for every control to 
  363.     // get the sizing
  364.     POINT origin = {0, 0};
  365.     SIZE max = {0, 0};
  366.     for (i = 0; i < n; i++)
  367.     {
  368.         LPTSTR tszName = AllocLPTSTR(os.pdoi[i].tszName);
  369.         CDeviceViewText *pText = pView->AddText(
  370.             (HFONT)ui.m_uig.GetFont(UIE_DEVOBJ),
  371.             ui.m_uig.GetTextColor(UIE_DEVOBJ),
  372.             ui.m_uig.GetBkColor(UIE_DEVOBJ),
  373.             origin,
  374.             tszName);
  375.         free(tszName);
  376.         if (!pText)
  377.             return E_FAIL;
  378.         SIZE tsize = GetRectSize(pText->GetRect());
  379.         if (tsize.cx > max.cx)
  380.             max.cx = tsize.cx;
  381.         if (tsize.cy > max.cy)
  382.             max.cy = tsize.cy;
  383.     }
  384.  
  385.     // Find out if we should use one column or two columns if this is a kbd device.
  386.     BOOL bUseTwoColumns = FALSE;
  387.     if (LOBYTE(LOWORD(ui.m_didi.dwDevType)) == DI8DEVTYPE_KEYBOARD &&
  388.         ((g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1) - max.cx >= MINLISTVIEWCALLOUTWIDTH)
  389.         bUseTwoColumns = TRUE;
  390.  
  391.     // calculate max callout height based on the two possible fonts
  392.     int cmaxh = 0,
  393.         ch = 2 + GetTextHeight((HFONT)ui.m_uig.GetFont(UIE_CALLOUT)),
  394.         chh = 2 + GetTextHeight((HFONT)ui.m_uig.GetFont(UIE_CALLOUTHIGH));
  395.     if (ch > cmaxh)
  396.         cmaxh = ch;
  397.     if (chh > cmaxh)
  398.         cmaxh = chh;
  399.  
  400.     // calculate the bigger of text/callout
  401.     int h = 0;
  402.     if (cmaxh > h)
  403.         h = cmaxh;
  404.     if (max.cy > h)
  405.         h = max.cy;
  406.  
  407.     // calculate vertical offsets of text/callout within max spacing
  408.     int to = (h - max.cy) / 2,
  409.         co = (h - cmaxh) / 2;
  410.  
  411.     // max width for text is half of the view window
  412.     if (max.cx > ((g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1))
  413.         max.cx = ((g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1);
  414.  
  415.     // go back through all the controls and place the text while
  416.     // creating the corresponding callouts
  417.     HDC hDC = CreateCompatibleDC(NULL);
  418.     CPaintHelper ph(ui.m_uig, hDC);
  419.     ph.SetElement(UIE_DEVOBJ);
  420.     int at = 0;  // Start at second row since first row is used for header. Also half row spacing
  421.     for (i = 0; i < n; i++)
  422.     {
  423.         // reposition the text
  424.         CDeviceViewText *pText = pView->GetText(i);
  425.         if (!pText)
  426.         {
  427.             DeleteDC(hDC);
  428.             return E_FAIL;
  429.         }
  430.  
  431.         SIZE s = GetRectSize(pText->GetRect());
  432.         if (bUseTwoColumns)
  433.         {
  434.             int iXOffset = i & 1 ? ((g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1) : 0;
  435.  
  436.             RECT rect = {iXOffset,
  437.                          at + to,
  438.                          max.cx + iXOffset,
  439.                          at + to + s.cy};
  440.             // Get the rectangle that is actually used.
  441.             RECT adjrect = rect;
  442.             if (hDC)
  443.             {
  444.                 DrawText(hDC, pText->GetText(), -1, &adjrect, DT_NOPREFIX|DT_CALCRECT);
  445.                 // If the rect actually used is smaller than the space available, use the smaller rect and align to right.
  446.                 if (adjrect.right < rect.right)
  447.                     rect.left += rect.right - adjrect.right;
  448.             }
  449.             pText->SetRect(rect);
  450.         }
  451.         else
  452.         {
  453.             RECT rect = {0, at + to, max.cx /*> ((g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1) ?
  454.                          ((g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1) : max.cx*/, at + to + s.cy};
  455.             pText->SetRect(rect);
  456.         }
  457.  
  458.         // create the control
  459.         CDeviceControl *pControl = pView->NewControl();
  460.         if (!pControl)
  461.         {
  462.             DeleteDC(hDC);
  463.             return E_FAIL;
  464.         }
  465.  
  466.         // position it
  467.         RECT rect = {max.cx + 10, at, (g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1, at + h};
  468.         // If single column, extend callout all the way to right end of view window
  469.         if (!bUseTwoColumns)
  470.             rect.right = g_sizeImage.cx - DEFAULTVIEWSBWIDTH;
  471.         // If this is a keyboard, move to right column on odd numbered controls.
  472.         if (bUseTwoColumns && (i & 1))
  473.         {
  474.             rect.left += (g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1;
  475.             rect.right = g_sizeImage.cx - DEFAULTVIEWSBWIDTH;
  476.         }
  477.         pControl->SetCalloutMaxRect(rect);
  478.  
  479.         // align it
  480.         pControl->SetAlignment(CAF_LEFT);
  481.  
  482.         // set approp offset
  483.         pControl->SetObjID(os.pdoi[i].dwType);
  484.  
  485.         // init it
  486.         pControl->Init();
  487.  
  488.         // go to next y coord
  489.         // If this is a keyboard, then only increase y when we are moving to even numbered controls.
  490.         if (!bUseTwoColumns || (i & 1))
  491.             at += h;
  492.     }
  493.     DeleteDC(hDC);
  494.  
  495.     // make selection/thumb images (just for kicks)
  496.     pView->MakeMissingImages();
  497.     
  498.     // calculate view dimensions (for scrolling)
  499.     pView->CalcDimensions();
  500.  
  501.     return S_OK;
  502. }
  503.  
  504. // Creates a single view with an error message.  Should not fail.
  505. HRESULT PopulateErrorView(CDeviceUI &ui)
  506. {
  507.     // create the new view
  508.     CDeviceView *pView = ui.NewView();
  509.     if (!pView)
  510.         return E_FAIL;
  511.  
  512.     // add text objects containing error message
  513.     pView->AddWrappedLineOfText(
  514.         (HFONT)ui.m_uig.GetFont(UIE_ERRORHEADER),
  515.         ui.m_uig.GetTextColor(UIE_ERRORHEADER),
  516.         ui.m_uig.GetBkColor(UIE_ERRORHEADER),
  517.         _T("Error!"));
  518.     pView->AddWrappedLineOfText(
  519.         (HFONT)ui.m_uig.GetFont(UIE_ERRORMESSAGE),
  520.         ui.m_uig.GetTextColor(UIE_ERRORMESSAGE),
  521.         ui.m_uig.GetBkColor(UIE_ERRORMESSAGE),
  522.         _T("Could not create views for device."));
  523.  
  524.     pView->MakeMissingImages();
  525.  
  526.     return S_OK;
  527. }
  528.