Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

567 lines
16 KiB

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