home *** CD-ROM | disk | FTP | other *** search
/ Beginning Direct3D Game Programming / Direct3D.iso / directx / dxf / samples / multimedia / directinput / diconfig / populate.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-06  |  13.2 KB  |  497 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-2000 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.                     CBitmap *pbm = CBitmap::CreateViaD3DX(tszImagePath, ui.m_uig.GetSurface3D());
  224.                     traceSTR(info.tszImagePath);
  225.                     traceHEXPTR(pbm);
  226.                     traceDWORD(dwOffset);
  227.                     free(tszImagePath);
  228.                     tszImagePath = NULL;
  229.                     if (!pbm)
  230.                     {
  231.                         etrace(_T("Could not create image from path.\n"));
  232.                         return E_FAIL;
  233.                     }
  234.  
  235.                     // set the view's image
  236.                     assert(pbm != NULL);
  237.                     pView->SetImage(pbm);    // setimage steals the bitmap pointer
  238.                     assert(pbm == NULL);
  239.  
  240.                     // add conversion from offset to view
  241.                     offset_view.add(dwOffset, nView);
  242.                 }
  243.             }
  244.     }
  245.  
  246.     {
  247.         tracescope(ts2, _T("Second Pass...\n"));
  248.  
  249.         for (i = 0; i < dwNumElements; i++)
  250.         {
  251.             DWORD dwFlags = dih.lprgImageInfoArray[i].dwFlags;
  252.  
  253.             if (dwFlags & DIDIFT_OVERLAY)
  254.             {
  255.                 LPDIDEVICEIMAGEINFOW lpInfoBase = dih.lprgImageInfoArray;
  256.                 DWORD index = i;
  257.                 {
  258.                     tracescope(ts1, _T("AddControlInfo()...\n"));
  259.                     traceHEXPTR(lpInfoBase);
  260.                     traceDWORD(index);
  261.  
  262.                     if (lpInfoBase == NULL)
  263.                     {
  264.                         etrace(_T("lpInfoBase NULL\n"));
  265.                         return E_FAIL;
  266.                     }
  267.  
  268.                     DIDEVICEIMAGEINFOW &info = lpInfoBase[index];
  269.  
  270.                     int nViewIndex = 0;
  271.                     
  272.                     if (!offset_view.getright(info.dwViewID, nViewIndex))
  273.                     {
  274.                         etrace(_T("Could not get view index\n"));
  275.                         return E_FAIL;
  276.                     }
  277.  
  278.                     if (nViewIndex < 0 || nViewIndex >= ui.GetNumViews())
  279.                     {
  280.                         etrace1(_T("Invalid view index %d\n"), nViewIndex);
  281.                         return E_FAIL;
  282.                     }
  283.  
  284.                     CDeviceView *pView = ui.GetView(nViewIndex);
  285.                     if (!pView)
  286.                     {
  287.                         etrace1(_T("\n"), nViewIndex);
  288.                         return E_FAIL;
  289.                     }
  290.  
  291.                     CDeviceControl *pControl = pView->NewControl();
  292.                     int nControl = pControl->GetControlIndex();
  293.  
  294.                     tracescope(ts2, _T("Adding Control "));
  295.                     trace4(_T("%d (info index %u) to view %d (info index %u)\n"), nControl, index, nViewIndex, info.dwViewID);
  296.  
  297.                     traceDWORD(info.dwObjID);
  298.                     traceDWORD(info.dwcValidPts);
  299.                     traceRECT(info.rcCalloutRect);
  300.                     traceRECT(info.rcOverlay);
  301.                     traceHEX(info.dwTextAlign);
  302.                     traceSTR(info.tszImagePath);
  303.  
  304.                     pControl->SetObjID(info.dwObjID);
  305.                     pControl->SetLinePoints(int(info.dwcValidPts), info.rgptCalloutLine);
  306.                     pControl->SetCalloutMaxRect(info.rcCalloutRect);
  307.                     pControl->SetAlignment(info.dwTextAlign);
  308.                     if (info.tszImagePath)
  309.                     {
  310.                         LPTSTR tszOverlayPath = AllocLPTSTR(info.tszImagePath);
  311.                         if (tszOverlayPath)
  312.                             pControl->SetOverlayPath(tszOverlayPath);
  313.                         free(tszOverlayPath);
  314.                         tszOverlayPath = NULL;
  315.                     }
  316.                     pControl->SetOverlayRect(info.rcOverlay);
  317.                     pControl->Init();
  318.                 }
  319.             }
  320.         }
  321.     }
  322.  
  323.     return S_OK;
  324. }
  325.  
  326. // Enumerates the controls on the device and creates one big list
  327. // view for the device.  Fails if it can't enumerate for some reason.
  328. HRESULT PopulateListView(CDeviceUI &ui)
  329. {
  330.     int i;
  331.     HRESULT hr = S_OK;
  332.  
  333.     // we must have the device interface
  334.     if (!ui.m_lpDID)
  335.         return E_FAIL;
  336.  
  337.     // create one view
  338.     CDeviceView *pView = ui.NewView();
  339.     if (!pView)
  340.         return E_FAIL;
  341.  
  342.     // enable scrolling on it
  343.     pView->EnableScrolling();
  344.  
  345.     // get list of controls
  346.     DIDEVOBJSTRUCT os;
  347.     hr = FillDIDeviceObjectStruct(os, ui.m_lpDID);
  348.     if (FAILED(hr))
  349.         return hr;
  350.  
  351.     // if there aren't any, fail
  352.     int n = os.nObjects;
  353.     if (n < 1)
  354.         return E_FAIL;
  355.  
  356.     // run through and create a text for every control to 
  357.     // get the sizing
  358.     POINT origin = {0, 0};
  359.     SIZE max = {0, 0};
  360.     for (i = 0; i < n; i++)
  361.     {
  362.         LPTSTR tszName = AllocLPTSTR(os.pdoi[i].tszName);
  363.         CDeviceViewText *pText = pView->AddText(
  364.             (HFONT)ui.m_uig.GetFont(UIE_DEVOBJ),
  365.             ui.m_uig.GetTextColor(UIE_DEVOBJ),
  366.             ui.m_uig.GetBkColor(UIE_DEVOBJ),
  367.             origin,
  368.             tszName);
  369.         free(tszName);
  370.         if (!pText)
  371.             return E_FAIL;
  372.         SIZE tsize = GetRectSize(pText->GetRect());
  373.         if (tsize.cx > max.cx)
  374.             max.cx = tsize.cx;
  375.         if (tsize.cy > max.cy)
  376.             max.cy = tsize.cy;
  377.     }
  378.  
  379.     // Find out if we should use one column or two columns if this is a kbd device.
  380.     BOOL bUseTwoColumns = FALSE;
  381.     if (LOBYTE(LOWORD(ui.m_didi.dwDevType)) == DI8DEVTYPE_KEYBOARD &&
  382.         ((g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1) - max.cx >= MINLISTVIEWCALLOUTWIDTH)
  383.         bUseTwoColumns = TRUE;
  384.  
  385.     // calculate max callout height based on the two possible fonts
  386.     int cmaxh = 0,
  387.         ch = 2 + GetTextHeight((HFONT)ui.m_uig.GetFont(UIE_CALLOUT)),
  388.         chh = 2 + GetTextHeight((HFONT)ui.m_uig.GetFont(UIE_CALLOUTHIGH));
  389.     if (ch > cmaxh)
  390.         cmaxh = ch;
  391.     if (chh > cmaxh)
  392.         cmaxh = chh;
  393.     
  394.     // calculate the bigger of text/callout
  395.     int h = 0;
  396.     if (cmaxh > h)
  397.         h = cmaxh;
  398.     if (max.cy > h)
  399.         h = max.cy;
  400.  
  401.     // calculate vertical offsets of text/callout within max spacing
  402.     int to = (h - max.cy) / 2,
  403.         co = (h - cmaxh) / 2;
  404.  
  405.     // go back through all the controls and place the text while
  406.     // creating the corresponding callouts
  407.     int at = 0;
  408.     for (i = 0; i < n; i++)
  409.     {
  410.         // reposition the text
  411.         CDeviceViewText *pText = pView->GetText(i);
  412.         if (!pText)
  413.             return E_FAIL;
  414.         SIZE s = GetRectSize(pText->GetRect());
  415.         if (bUseTwoColumns)
  416.         {
  417.             int iXOffset = i & 1 ? ((g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1) : 0;
  418.  
  419.             RECT rect = {iXOffset,
  420.                          at + to,
  421.                          max.cx + iXOffset,
  422.                          at + to + s.cy};
  423.             pText->SetRect(rect);
  424.         }
  425.         else
  426.         {
  427.             RECT rect = {0, at + to, max.cx, at + to + s.cy};
  428.             pText->SetRect(rect);
  429.         }
  430.  
  431.         // create the control
  432.         CDeviceControl *pControl = pView->NewControl();
  433.         if (!pControl)
  434.             return E_FAIL;
  435.  
  436.         // position it
  437.         RECT rect = {max.cx + 10, at, (g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1, at + h};
  438.         // If single column, extend callout all the way to right end of view window
  439.         if (!bUseTwoColumns)
  440.             rect.right = g_sizeImage.cx - DEFAULTVIEWSBWIDTH;
  441.         // If this is a keyboard, move to right column on odd numbered controls.
  442.         if (bUseTwoColumns && (i & 1))
  443.         {
  444.             rect.left += (g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1;
  445.             rect.right = g_sizeImage.cx - DEFAULTVIEWSBWIDTH;
  446.         }
  447.         pControl->SetCalloutMaxRect(rect);
  448.  
  449.         // align it
  450.         pControl->SetAlignment(CAF_LEFT);
  451.  
  452.         // set approp offset
  453.         pControl->SetObjID(os.pdoi[i].dwType);
  454.  
  455.         // init it
  456.         pControl->Init();
  457.  
  458.         // go to next y coord
  459.         // If this is a keyboard, then only increase y when we are moving to even numbered controls.
  460.         if (!bUseTwoColumns || (i & 1))
  461.             at += h;
  462.     }
  463.  
  464.     // make selection/thumb images (just for kicks)
  465.     pView->MakeMissingImages();
  466.     
  467.     // calculate view dimensions (for scrolling)
  468.     pView->CalcDimensions();
  469.  
  470.     return S_OK;
  471. }
  472.  
  473. // Creates a single view with an error message.  Should not fail.
  474. HRESULT PopulateErrorView(CDeviceUI &ui)
  475. {
  476.     // create the new view
  477.     CDeviceView *pView = ui.NewView();
  478.     if (!pView)
  479.         return E_FAIL;
  480.  
  481.     // add text objects containing error message
  482.     pView->AddWrappedLineOfText(
  483.         (HFONT)ui.m_uig.GetFont(UIE_ERRORHEADER),
  484.         ui.m_uig.GetTextColor(UIE_ERRORHEADER),
  485.         ui.m_uig.GetBkColor(UIE_ERRORHEADER),
  486.         _T("Error!"));
  487.     pView->AddWrappedLineOfText(
  488.         (HFONT)ui.m_uig.GetFont(UIE_ERRORMESSAGE),
  489.         ui.m_uig.GetTextColor(UIE_ERRORMESSAGE),
  490.         ui.m_uig.GetBkColor(UIE_ERRORMESSAGE),
  491.         _T("Could not create views for device."));
  492.  
  493.     pView->MakeMissingImages();
  494.  
  495.     return S_OK;
  496. }
  497.