Source code of Windows XP (NT5)
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.

1553 lines
34 KiB

  1. //-----------------------------------------------------------------------------
  2. // File: cdeviceview.cpp
  3. //
  4. // Desc: CDeviceView is a window class derived from CFlexWnd. It represents
  5. // the device view window in which the device and callouts are drawn.
  6. // Each CDeviceView only represents one view. A device that has more
  7. // than one view should have a corresponding number of CDeviceView for it.
  8. //
  9. // Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  10. //-----------------------------------------------------------------------------
  11. #include "common.hpp"
  12. CDeviceView::CDeviceView(CDeviceUI &ui) :
  13. m_ui(ui),
  14. m_pbmImage(NULL),
  15. m_pbmThumb(NULL),
  16. m_pbmSelThumb(NULL),
  17. m_SuperState(0),
  18. m_State(0),
  19. m_SubState(0),
  20. m_OldSuperState(0),
  21. m_OldState(0),
  22. m_OldSubState(0),
  23. m_pControlContext(NULL),
  24. m_ptszImagePath(NULL),
  25. m_bScrollEnable(FALSE),
  26. m_nScrollOffset(0),
  27. m_nViewHeight(g_sizeImage.cy),
  28. m_bForcePaint(FALSE),
  29. m_bControlHeaderClipped(FALSE),
  30. m_bActionHeaderClipped(FALSE)
  31. {
  32. ZeroMemory(m_HeaderRectControl, sizeof(m_HeaderRectControl));
  33. ZeroMemory(m_HeaderRectAction, sizeof(m_HeaderRectAction));
  34. m_ptNextWLOText.x = m_ptNextWLOText.y = 0;
  35. }
  36. CDeviceView::~CDeviceView()
  37. {
  38. Unpopulate();
  39. }
  40. CDeviceControl *CDeviceView::NewControl()
  41. {
  42. CDeviceControl *pControl = new CDeviceControl(m_ui, *this);
  43. if (!pControl)
  44. return NULL;
  45. m_arpControl.SetAtGrow(m_arpControl.GetSize(), pControl);
  46. return pControl;
  47. }
  48. void CDeviceView::Remove(CDeviceControl *pControl)
  49. {
  50. if (pControl == NULL)
  51. return;
  52. int i = pControl->GetControlIndex();
  53. if (i < 0 || i >= GetNumControls())
  54. {
  55. assert(0);
  56. return;
  57. }
  58. if (pControl == m_pControlContext)
  59. m_pControlContext = NULL;
  60. if (m_arpControl[i] != NULL)
  61. delete m_arpControl[i];
  62. m_arpControl[i] = NULL;
  63. m_arpControl.RemoveAt(i);
  64. Invalidate();
  65. }
  66. void CDeviceView::RemoveAll(BOOL bUser)
  67. {
  68. m_pControlContext = NULL;
  69. for (int i = 0; i < GetNumControls(); i++)
  70. {
  71. if (m_arpControl[i] != NULL)
  72. delete m_arpControl[i];
  73. m_arpControl[i] = NULL;
  74. }
  75. m_arpControl.RemoveAll();
  76. Invalidate();
  77. }
  78. void CDeviceView::Unpopulate(BOOL bInternalOnly)
  79. {
  80. DisableScrollBar();
  81. m_bScrollEnable = FALSE;
  82. if (m_pbmImage != NULL)
  83. delete m_pbmImage;
  84. if (m_pbmThumb != NULL)
  85. delete m_pbmThumb;
  86. if (m_pbmSelThumb != NULL)
  87. delete m_pbmSelThumb;
  88. m_pbmImage = NULL;
  89. m_pbmThumb = NULL;
  90. m_pbmSelThumb = NULL;
  91. free(m_ptszImagePath);
  92. m_ptszImagePath = NULL;
  93. if (!bInternalOnly)
  94. RemoveAll(FALSE);
  95. for (int i = 0; i < m_arpText.GetSize(); i++)
  96. {
  97. if (m_arpText[i])
  98. delete m_arpText[i];
  99. m_arpText[i] = NULL;
  100. }
  101. m_arpText.RemoveAll();
  102. }
  103. void AssureSize(CBitmap *&pbm, SIZE to)
  104. {
  105. if (!pbm)
  106. return;
  107. SIZE from;
  108. if (!pbm->GetSize(&from))
  109. return;
  110. if (from.cx >= to.cx && from.cy >= to.cy)
  111. return;
  112. CBitmap *nbm = CBitmap::Create(to, RGB(0,0,0));
  113. if (!nbm)
  114. return;
  115. HDC hDC = nbm->BeginPaintInto();
  116. pbm->Draw(hDC);
  117. nbm->EndPaintInto(hDC);
  118. delete pbm;
  119. pbm = nbm;
  120. nbm = NULL;
  121. }
  122. CBitmap *CDeviceView::GrabViewImage()
  123. {
  124. CBitmap *pbm = CBitmap::Create(GetClientSize(), RGB(0, 0, 0), NULL);
  125. if (!pbm)
  126. return NULL;
  127. HDC hDC = pbm->BeginPaintInto();
  128. if (!hDC)
  129. {
  130. delete pbm;
  131. return NULL;
  132. }
  133. OnPaint(hDC);
  134. pbm->EndPaintInto(hDC);
  135. return pbm;
  136. }
  137. void CDeviceView::MakeMissingImages()
  138. {
  139. // if (m_pbmImage)
  140. // AssureSize(m_pbmImage, g_sizeImage);
  141. if (m_pbmThumb == NULL)
  142. {
  143. if (m_pbmImage)
  144. m_pbmThumb = m_pbmImage->CreateResizedTo(g_sizeThumb);
  145. else
  146. {
  147. CBitmap *pbmImage = GrabViewImage();
  148. if (pbmImage)
  149. {
  150. AssureSize(pbmImage, g_sizeImage);
  151. m_pbmThumb = pbmImage->CreateResizedTo(g_sizeThumb);
  152. }
  153. delete pbmImage;
  154. }
  155. }
  156. if (m_pbmThumb == NULL)
  157. return;
  158. if (m_pbmSelThumb == NULL)
  159. {
  160. m_pbmSelThumb = m_pbmThumb->Dup();
  161. if (m_pbmSelThumb != NULL)
  162. {
  163. HDC hDC = m_pbmSelThumb->BeginPaintInto();
  164. {
  165. CPaintHelper ph(m_ui.m_uig, hDC);
  166. ph.SetPen(UIP_SELTHUMB);
  167. ph.Rectangle(0, 0, g_sizeThumb.cx, g_sizeThumb.cy, UIR_OUTLINE);
  168. }
  169. m_pbmSelThumb->EndPaintInto(hDC);
  170. }
  171. }
  172. }
  173. void CDeviceView::OnPaint(HDC hDC)
  174. {
  175. HDC hBDC = NULL, hODC = NULL;
  176. CBitmap *pbm = NULL;
  177. if (!InRenderMode())
  178. {
  179. hODC = hDC;
  180. pbm = CBitmap::Create(GetClientSize(), RGB(0, 0, 0), hDC);
  181. if (pbm != NULL)
  182. {
  183. hBDC = pbm->BeginPaintInto();
  184. if (hBDC != NULL)
  185. hDC = hBDC;
  186. }
  187. }
  188. // Black-fill first
  189. SIZE fillsz = GetClientSize();
  190. RECT fillrc = {0, 0, fillsz.cx, fillsz.cy};
  191. FillRect(hDC, &fillrc, (HBRUSH)GetStockObject(BLACK_BRUSH));
  192. if (m_pbmImage != NULL)
  193. m_pbmImage->Blend(hDC);
  194. BOOL bScroll = m_bScrollEnable && m_sb.m_hWnd;
  195. int sdc = 0;
  196. if (bScroll)
  197. {
  198. sdc = SaveDC(hDC);
  199. OffsetViewportOrgEx(hDC, 0, -m_nScrollOffset + g_iListHeaderHeight, NULL);
  200. }
  201. else
  202. if (m_bScrollEnable)
  203. {
  204. sdc = SaveDC(hDC);
  205. OffsetViewportOrgEx(hDC, 0, g_iListHeaderHeight, NULL);
  206. }
  207. int miny = 0 + m_nScrollOffset;
  208. int maxy = g_sizeImage.cy + m_nScrollOffset;
  209. int t, nt = GetNumTexts();
  210. for (t = 0; t < nt; t++)
  211. {
  212. CDeviceViewText *pText = m_arpText[t];
  213. if (pText != NULL &&
  214. !(pText->GetMinY() > maxy || pText->GetMaxY() < miny))
  215. pText->OnPaint(hDC);
  216. }
  217. BOOL bCFGUIEdit = m_ui.m_uig.InEditMode();
  218. BOOL bEitherEditMode = bCFGUIEdit;
  219. //@@BEGIN_MSINTERNAL
  220. #ifdef DDKBUILD
  221. BOOL bEditLayout = m_ui.InEditMode();
  222. bEitherEditMode = bEitherEditMode || bEditLayout;
  223. #endif
  224. //@@END_MSINTERNAL
  225. int c, nc = GetNumControls();
  226. for (c = 0; c < nc; c++)
  227. if (m_arpControl[c] != NULL && m_arpControl[c]->HasOverlay() &&
  228. (m_arpControl[c]->IsHighlighted()
  229. //@@BEGIN_MSINTERNAL
  230. #ifdef DDKBUILD
  231. || InMoveOverlayStateForControl(m_arpControl[c])
  232. #endif
  233. //@@END_MSINTERNAL
  234. )
  235. && (bEitherEditMode || m_arpControl[c]->IsMapped()))
  236. m_arpControl[c]->DrawOverlay(hDC);
  237. for (c = 0; c < nc; c++)
  238. {
  239. CDeviceControl *pControl = m_arpControl[c];
  240. if (pControl != NULL && (bEitherEditMode || pControl->IsMapped()) &&
  241. !(pControl->GetMinY() > maxy || pControl->GetMaxY() < miny))
  242. pControl->OnPaint(hDC);
  243. }
  244. if (bScroll || m_bScrollEnable)
  245. {
  246. RestoreDC(hDC, sdc);
  247. sdc = 0;
  248. }
  249. // Black fill the top portion if this is a list view
  250. if (bScroll)
  251. {
  252. GetClientRect(&fillrc);
  253. fillrc.bottom = g_iListHeaderHeight;
  254. FillRect(hDC, &fillrc, (HBRUSH)GetStockObject(BLACK_BRUSH));
  255. }
  256. // Print out the headers
  257. TCHAR tszHeader[MAX_PATH];
  258. // Control column
  259. //@@BEGIN_MSINTERNAL
  260. #ifdef DDKBUILD
  261. if (m_arpText.GetSize() > 2)
  262. /*
  263. //@@END_MSINTERNAL
  264. if (m_arpText.GetSize())
  265. //@@BEGIN_MSINTERNAL
  266. */
  267. #endif
  268. //@@END_MSINTERNAL
  269. {
  270. CPaintHelper ph(m_ui.m_uig, hDC);
  271. ph.SetElement(UIE_CALLOUT);
  272. for (int i = 0; i < 2; i++)
  273. {
  274. // Check if there are two columns, break out the 2nd iteration if not 2 columns.
  275. if (i == 1 && !(GetNumControls() > 1 &&
  276. m_arpControl[0]->GetCalloutMaxRect().top == m_arpControl[1]->GetCalloutMaxRect().top))
  277. break;
  278. RECT rcheader;
  279. if (m_arpText.GetSize())
  280. {
  281. // Control column
  282. LoadString(g_hModule, IDS_LISTHEADER_CTRL, tszHeader, MAX_PATH);
  283. DrawText(hDC, tszHeader, -1, &m_HeaderRectControl[i], DT_LEFT|DT_NOPREFIX|DT_END_ELLIPSIS);
  284. // Action column
  285. LoadString(g_hModule, IDS_LISTHEADER_ACTION, tszHeader, MAX_PATH);
  286. DrawText(hDC, tszHeader, -1, &m_HeaderRectAction[i], DT_CENTER|DT_NOPREFIX|DT_END_ELLIPSIS);
  287. }
  288. }
  289. }
  290. //@@BEGIN_MSINTERNAL
  291. #ifdef DDKBUILD
  292. if (bEditLayout)
  293. {
  294. CPaintHelper ph(m_ui.m_uig, hDC);
  295. ph.SetElement(UIE_VIEWBORDER);
  296. RECT rect;
  297. GetClientRect(&rect);
  298. if (bScroll)
  299. rect.right -= DEFAULTVIEWSBWIDTH;
  300. ph.Rectangle(rect);
  301. }
  302. #endif
  303. //@@END_MSINTERNAL
  304. if (!InRenderMode())
  305. {
  306. if (pbm != NULL)
  307. {
  308. if (hBDC != NULL)
  309. {
  310. pbm->EndPaintInto(hBDC);
  311. pbm->Draw(hODC);
  312. }
  313. delete pbm;
  314. }
  315. }
  316. }
  317. int CDeviceView::GetNumControls()
  318. {
  319. return m_arpControl.GetSize();
  320. }
  321. CDeviceControl *CDeviceView::GetControl(int nControl)
  322. {
  323. if (nControl >= 0 && nControl < GetNumControls())
  324. return m_arpControl[nControl];
  325. else
  326. return NULL;
  327. }
  328. CBitmap *CDeviceView::GetImage(DVIMAGE dvi)
  329. {
  330. switch (dvi)
  331. {
  332. case DVI_IMAGE: return m_pbmImage;
  333. case DVI_THUMB: return m_pbmThumb;
  334. case DVI_SELTHUMB: return m_pbmSelThumb;
  335. default:
  336. return NULL;
  337. }
  338. }
  339. void CDeviceView::OnMouseOver(POINT point, WPARAM wParam)
  340. {
  341. if (m_bScrollEnable && m_sb.m_hWnd)
  342. point.y += m_nScrollOffset;
  343. //@@BEGIN_MSINTERNAL
  344. #ifdef DDKBUILD
  345. if (InEditState())
  346. {
  347. StateEvent(point, FALSE, TRUE, wParam);
  348. return;
  349. }
  350. #endif
  351. //@@END_MSINTERNAL
  352. // Check if we are over a control
  353. POINT adjPt = point;
  354. if (m_bScrollEnable) adjPt.y -= g_iListHeaderHeight;
  355. int c, nc = GetNumControls();
  356. for (c = 0; c < nc; c++)
  357. if (m_arpControl[c] != NULL && m_arpControl[c]->HitTest(adjPt) != DCHT_NOHIT)
  358. {
  359. m_arpControl[c]->OnMouseOver(adjPt);
  360. return;
  361. }
  362. // Check if we are over a viewtext
  363. nc = GetNumTexts();
  364. for (c = 0; c < nc; c++)
  365. if (m_arpText[c] != NULL && m_arpText[c]->HitTest(adjPt) != DCHT_NOHIT)
  366. {
  367. m_arpText[c]->OnMouseOver(adjPt);
  368. return;
  369. }
  370. CFlexWnd::s_ToolTip.SetEnable(FALSE);
  371. DEVICEUINOTIFY uin;
  372. uin.msg = DEVUINM_MOUSEOVER;
  373. uin.from = DEVUINFROM_VIEWWND;
  374. uin.mouseover.point = point;
  375. m_ui.Notify(uin);
  376. }
  377. void CDeviceView::OnClick(POINT point, WPARAM wParam, BOOL bLeft)
  378. {
  379. if (m_bScrollEnable && m_sb.m_hWnd)
  380. point.y += m_nScrollOffset;
  381. //@@BEGIN_MSINTERNAL
  382. #ifdef DDKBUILD
  383. if (InEditState())
  384. {
  385. StateEvent(point, TRUE, bLeft, wParam);
  386. return;
  387. }
  388. #endif
  389. //@@END_MSINTERNAL
  390. POINT adjPt = point;
  391. if (m_bScrollEnable) adjPt.y -= g_iListHeaderHeight;
  392. int c, nc = GetNumControls();
  393. for (c = 0; c < nc; c++)
  394. // adjPt is the adjust click point for scrolling list view
  395. if (m_arpControl[c] != NULL && m_arpControl[c]->HitTest(adjPt) != DCHT_NOHIT)
  396. {
  397. m_arpControl[c]->OnClick(adjPt, bLeft);
  398. return;
  399. }
  400. //@@BEGIN_MSINTERNAL
  401. #ifdef DDKBUILD
  402. if (GetNumTexts() > 2)
  403. #endif
  404. //@@END_MSINTERNAL
  405. {
  406. for (c = 0; c < GetNumTexts(); ++c)
  407. if (m_arpControl[c] != NULL && m_arpText[c] != NULL)
  408. {
  409. RECT rc = m_arpText[c]->GetRect();
  410. if (PtInRect(&rc, adjPt))
  411. {
  412. m_arpControl[c]->OnClick(adjPt, bLeft);
  413. return;
  414. }
  415. }
  416. }
  417. //@@BEGIN_MSINTERNAL
  418. #ifdef DDKBUILD
  419. if (!bLeft && m_ui.InEditMode())
  420. {
  421. EditMenu(point);
  422. return;
  423. }
  424. #endif
  425. //@@END_MSINTERNAL
  426. // Send notification
  427. DEVICEUINOTIFY uin;
  428. uin.msg = DEVUINM_CLICK;
  429. uin.from = DEVUINFROM_VIEWWND;
  430. uin.click.bLeftButton = bLeft;
  431. m_ui.Notify(uin);
  432. }
  433. void CDeviceView::OnDoubleClick(POINT point, WPARAM wParam, BOOL bLeft)
  434. {
  435. if (m_bScrollEnable && m_sb.m_hWnd)
  436. point.y += m_nScrollOffset;
  437. POINT adjPt = point;
  438. if (m_bScrollEnable) adjPt.y -= g_iListHeaderHeight;
  439. int c, nc = GetNumControls();
  440. for (c = 0; c < nc; c++)
  441. if (m_arpControl[c] != NULL && m_arpControl[c]->HitTest(adjPt) != DCHT_NOHIT)
  442. {
  443. m_arpControl[c]->OnClick(adjPt, bLeft, TRUE);
  444. return;
  445. }
  446. for (c = 0; c < GetNumTexts(); ++c)
  447. if (m_arpControl[c] != NULL && m_arpText[c] != NULL)
  448. {
  449. RECT rc = m_arpText[c]->GetRect();
  450. if (PtInRect(&rc, adjPt))
  451. {
  452. m_arpControl[c]->OnClick(adjPt, bLeft, TRUE);
  453. return;
  454. }
  455. }
  456. DEVICEUINOTIFY uin;
  457. uin.msg = DEVUINM_DOUBLECLICK;
  458. uin.from = DEVUINFROM_VIEWWND;
  459. uin.click.bLeftButton = bLeft;
  460. m_ui.Notify(uin);
  461. }
  462. void CDeviceView::OnWheel(POINT point, WPARAM wParam)
  463. {
  464. if (!m_bScrollEnable) return;
  465. if (m_sb.GetMin() == m_sb.GetMax()) return;
  466. int nPage = MulDiv(m_sb.GetPage(), 9, 10) >> 1; // Half a page at a time
  467. if ((int)wParam >= 0)
  468. m_sb.AdjustPos(-nPage);
  469. else
  470. m_sb.AdjustPos(nPage);
  471. m_nScrollOffset = m_sb.GetPos();
  472. Invalidate();
  473. }
  474. //@@BEGIN_MSINTERNAL
  475. #ifdef DDKBUILD
  476. enum {
  477. IDEC_MOVECALLOUT = 1,
  478. IDEC_REDEFINECALLOUTMAX,
  479. IDEC_REALIGNCALLOUT,
  480. IDEC_REDEFINELINE,
  481. IDEC_RESELECTCONTROL,
  482. IDEC_REMOVECALLOUT,
  483. IDEC_SELECTIMAGES,
  484. IDEC_NEWVIEW,
  485. IDEC_NEWCALLOUT,
  486. IDEC_REMOVEALLCALLOUTS,
  487. IDEC_REMOVEVIEW,
  488. IDEC_REMOVEALLVIEWS,
  489. IDEC_SAVEOREXPORT,
  490. IDEC_SELECTOVERLAY,
  491. IDEC_MOVEOVERLAY,
  492. };
  493. BOOL CDeviceView::InMoveOverlayStateForControl(CDeviceControl *pControl)
  494. {
  495. return m_State == IDEC_MOVEOVERLAY && m_pControlContext == pControl && pControl != NULL;
  496. }
  497. void CDeviceView::EditMenu(POINT point, CDeviceControl *pControl)
  498. {
  499. static const struct ITEM {
  500. UINT uID; LPCTSTR tszName;
  501. } itemC[] = {
  502. {0, _T("Callout Edit Menu")},
  503. {0, NULL},
  504. {IDEC_MOVECALLOUT, _T("Move Callout")},
  505. {0, NULL},
  506. {IDEC_REDEFINECALLOUTMAX, _T("Redefine Callout Max")},
  507. {IDEC_REALIGNCALLOUT, _T("Realign Callout")},
  508. {IDEC_REDEFINELINE, _T("Redefine Line")},
  509. {IDEC_SELECTOVERLAY, _T("Select Overlay")},
  510. {IDEC_MOVEOVERLAY, _T("Move Overlay")},
  511. {0, NULL},
  512. {IDEC_RESELECTCONTROL, _T("Reselect Control")},
  513. {0, NULL},
  514. {IDEC_REMOVECALLOUT, _T("Remove Callout")},
  515. {0,NULL}
  516. }, itemV[] = {
  517. {0, _T("View Edit Menu")},
  518. {0, NULL},
  519. {IDEC_SELECTIMAGES, _T("Select Image(s)")},
  520. {0, NULL},
  521. {IDEC_NEWVIEW, _T("New View")},
  522. {IDEC_NEWCALLOUT, _T("New Callout")},
  523. {0, NULL},
  524. {IDEC_REMOVEALLCALLOUTS, _T("Remove All Callouts")},
  525. {0, NULL},
  526. {IDEC_REMOVEVIEW, _T("Remove View")},
  527. {IDEC_REMOVEALLVIEWS, _T("Remove All Views")},
  528. {0, NULL},
  529. {IDEC_SAVEOREXPORT, _T("Save/Export")},
  530. {0,NULL}
  531. };
  532. static const int numitemsC = sizeof(itemC) / sizeof(ITEM) - 1;
  533. static const int numitemsV = sizeof(itemV) / sizeof(ITEM) - 1;
  534. const ITEM *item = pControl ? itemC : itemV;
  535. int numitems = pControl ? numitemsC : numitemsV;
  536. HMENU hMenu = CreatePopupMenu();
  537. for (int i = 0; i < numitems; i++)
  538. if (item[i].tszName == NULL)
  539. AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
  540. else
  541. if (item[i].uID != 0)
  542. AppendMenu(hMenu, MF_STRING, item[i].uID, item[i].tszName);
  543. else
  544. AppendMenu(hMenu, MF_STRING | MF_GRAYED, 0, item[i].tszName);
  545. m_pControlContext = pControl;
  546. CFlexWnd::s_ToolTip.SetEnable(FALSE);
  547. POINT cursor;
  548. GetCursorPos(&cursor);
  549. TrackPopupMenuEx(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_LEFTBUTTON,
  550. cursor.x, cursor.y, m_hWnd, NULL);
  551. DestroyMenu(hMenu);
  552. }
  553. void CDeviceView::SaveOrExport()
  554. {
  555. OPENFILENAME ofn;
  556. TCHAR tszFile[256] = _T("");
  557. ofn.lStructSize = sizeof(OPENFILENAME);
  558. ofn.hwndOwner = m_hWnd;
  559. ofn.hInstance = g_hModule;
  560. ofn.lpstrFilter = NULL;
  561. ofn.lpstrCustomFilter = NULL;
  562. ofn.nMaxCustFilter = 0;
  563. ofn.nFilterIndex = 0;
  564. ofn.lpstrFile = tszFile;
  565. ofn.nMaxFile = 256;
  566. ofn.lpstrFileTitle = NULL;
  567. ofn.nMaxFileTitle = 0;
  568. ofn.lpstrInitialDir = 0;
  569. ofn.lpstrTitle = NULL;
  570. ofn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
  571. ofn.lpstrDefExt = _T("cpp");
  572. ofn.lCustData = NULL;
  573. ofn.lpfnHook = NULL;
  574. ofn.lpTemplateName = NULL;
  575. if (!GetSaveFileName(&ofn))
  576. return;
  577. if (FAILED(ExportCodeTo(tszFile)))
  578. MessageBox(m_hWnd, _T("Failed."), _T("Failed."), MB_OK);
  579. }
  580. HRESULT CDeviceView::ExportCodeTo(LPCTSTR tszFile)
  581. {
  582. #ifdef UNICODE
  583. FILE *f = _wfopen(tszFile, _T("wt"));
  584. #define fpf fwprintf
  585. #else
  586. FILE *f = fopen(tszFile, _T("wt"));
  587. #define fpf fprintf
  588. #endif
  589. if (f == NULL)
  590. return E_FAIL;
  591. fpf(f, _T("CViewKey g_View[%d] =\n{\n"), GetNumControls());
  592. for (int i = 0; i < GetNumControls(); i++)
  593. m_arpControl[i]->ExportCodeTo(f);
  594. fpf(f, _T("};\n"));
  595. fclose(f);
  596. #undef fpf
  597. return S_OK;
  598. }
  599. HRESULT CDeviceControl::ExportCodeTo(FILE *f)
  600. {
  601. if (f == NULL)
  602. return E_FAIL;
  603. #ifdef UNICODE
  604. #define fpf fwprintf
  605. #else
  606. #define fpf fprintf
  607. #endif
  608. fpf(f, _T("\t{0, 0, 0, {DIK_,\t"));
  609. switch (m_dwCalloutAlign)
  610. {
  611. case CAF_LEFT: fpf(f, _T("CAF_LEFT, ")); break;
  612. case CAF_RIGHT: fpf(f, _T("CAF_RIGHT, ")); break;
  613. case CAF_TOP: fpf(f, _T("CAF_TOP, ")); break;
  614. case CAF_BOTTOM: fpf(f, _T("CAF_BOTTOM, ")); break;
  615. case CAF_TOPLEFT: fpf(f, _T("CAF_TOPLEFT, ")); break;
  616. case CAF_TOPRIGHT: fpf(f, _T("CAF_TOPRIGHT, ")); break;
  617. case CAF_BOTTOMLEFT: fpf(f, _T("CAF_BOTTOMLEFT, ")); break;
  618. case CAF_BOTTOMRIGHT: fpf(f, _T("CAF_BOTTOMRIGHT, ")); break;
  619. case 0: default: fpf(f, _T("0,")); break;
  620. }
  621. fpf(f, _T("%s, %d, {"), RECTSTR(m_rectCalloutMax), m_nLinePoints);
  622. for (int i = 0; i < m_nLinePoints; i++)
  623. fpf(f, _T("%s,"), POINTSTR(m_rgptLinePoint[i]));
  624. fpf(f, _T("}}},\n"));
  625. #undef fpf
  626. return S_OK;
  627. }
  628. LRESULT CDeviceView::OnCommand(WORD wNotifyCode, WORD wID, HWND hWnd)
  629. {
  630. // only handle menu messages
  631. if (wNotifyCode != 0)
  632. return FALSE;
  633. UINT cmd = (UINT)wID;
  634. switch (cmd)
  635. {
  636. case IDEC_SAVEOREXPORT:
  637. {
  638. BOOL b;
  639. b = WriteToINI();
  640. break;
  641. }
  642. case IDEC_MOVEOVERLAY:
  643. case IDEC_MOVECALLOUT:
  644. case IDEC_REDEFINECALLOUTMAX:
  645. case IDEC_REALIGNCALLOUT:
  646. case IDEC_REDEFINELINE:
  647. case IDEC_NEWCALLOUT:
  648. SetEditState(cmd);
  649. return TRUE;
  650. case IDEC_RESELECTCONTROL:
  651. if (m_pControlContext)
  652. m_pControlContext->ReselectControl();
  653. break;
  654. case IDEC_REMOVECALLOUT:
  655. if (m_pControlContext)
  656. m_ui.NoteDeleteControl(m_pControlContext);
  657. Remove(m_pControlContext);
  658. break;
  659. case IDEC_SELECTOVERLAY:
  660. if (m_pControlContext)
  661. m_pControlContext->SelectOverlay();
  662. break;
  663. case IDEC_SELECTIMAGES:
  664. SelectImages();
  665. break;
  666. case IDEC_NEWVIEW:
  667. m_ui.SetView(m_ui.UserNewView());
  668. break;
  669. case IDEC_REMOVEALLCALLOUTS:
  670. if (UserConfirm(g_hModule, m_hWnd, IDS_REMOVEALLCALLOUTS, IDS_CONFIRMREMOVEALLCALLOUTS))
  671. {
  672. m_ui.NoteDeleteAllControlsForView(this);
  673. RemoveAll();
  674. }
  675. break;
  676. case IDEC_REMOVEVIEW:
  677. if (UserConfirm(g_hModule, m_hWnd, IDS_REMOVEVIEW, IDS_CONFIRMREMOVEVIEW))
  678. {
  679. // you MUST return immediately after this call,
  680. // as this object will have been deleted!
  681. m_ui.NoteDeleteView(this);
  682. m_ui.Remove(this);
  683. return TRUE;
  684. }
  685. break;
  686. case IDEC_REMOVEALLVIEWS:
  687. if (UserConfirm(g_hModule, m_hWnd, IDS_REMOVEALLVIEWS, IDS_CONFIRMREMOVEALLVIEWS))
  688. {
  689. // you MUST return immediately after this call,
  690. // as this object (and all other views for this device)
  691. // will have been deleted!
  692. m_ui.NoteDeleteAllViews();
  693. m_ui.RemoveAll();
  694. return TRUE;
  695. }
  696. break;
  697. default:
  698. return FALSE;
  699. }
  700. m_pControlContext = NULL;
  701. return TRUE;
  702. }
  703. BOOL CDeviceView::InEditState()
  704. {
  705. return m_State != 0;
  706. }
  707. void CDeviceView::EndEditState()
  708. {
  709. m_SuperState = 0;
  710. m_State = 0;
  711. m_SubState = 0;
  712. m_pControlContext = NULL;
  713. IndicateState();
  714. ReleaseCapture();
  715. }
  716. void CDeviceView::SetEditState(UINT cmd)
  717. {
  718. m_State = cmd;
  719. m_SubState = 0;
  720. if (m_State == 0)
  721. {
  722. EndEditState();
  723. return;
  724. }
  725. switch (cmd)
  726. {
  727. case IDEC_NEWCALLOUT:
  728. if (!IsUnassignedOffsetAvailable())
  729. {
  730. FormattedMsgBox(g_hModule, m_hWnd, MB_OK | MB_ICONINFORMATION, IDS_TITLE_NONEWCONTROL, IDS_ERROR_OFFSETUNAVAIL);
  731. EndEditState();
  732. return;
  733. }
  734. m_pControlContext = NewControl();
  735. m_SuperState = cmd;
  736. m_State = cmd = IDEC_REDEFINECALLOUTMAX;
  737. // fallthrough
  738. case IDEC_REDEFINECALLOUTMAX:
  739. case IDEC_REALIGNCALLOUT:
  740. case IDEC_REDEFINELINE:
  741. case IDEC_MOVECALLOUT:
  742. case IDEC_MOVEOVERLAY:
  743. break;
  744. default:
  745. assert(0);
  746. break;
  747. }
  748. SetCapture();
  749. IndicateState(TRUE);
  750. }
  751. void CDeviceView::IndicateState(BOOL bFirst)
  752. {
  753. // see what's changed since last call
  754. BOOL bSuperStateChanged = m_SuperState != m_OldSuperState;
  755. BOOL bStateChanged = m_State != m_OldState;
  756. BOOL bSubStateChanged = m_SubState != m_OldSubState;
  757. // save to check for next call
  758. m_OldSuperState = m_SuperState;
  759. m_OldState = m_State;
  760. m_OldSubState = m_SubState;
  761. // if there is no state, just end indication
  762. if (m_State == 0)
  763. {
  764. m_ui.EndStateIndication();
  765. return;
  766. }
  767. // unless this is the first indication for an editing state or super state...
  768. if (!bFirst)
  769. {
  770. // do nothing if nothing's changed
  771. if (!(bSuperStateChanged || bStateChanged || bSubStateChanged))
  772. return;
  773. }
  774. // string to send to the ui for indication
  775. TCHAR str[1024] = _T("");
  776. // fill string as appropriate
  777. switch (m_State)
  778. {
  779. case IDEC_REDEFINECALLOUTMAX:
  780. wsprintf(str, _T("Left click where you want to place %s corner of the callout max rect."),
  781. m_SubState == 0 ? _T("a") : _T("the opposite"));
  782. break;
  783. case IDEC_REALIGNCALLOUT:
  784. _tcscpy(str, _T("Move the mouse to consider callout alignments within the max rect, and left click to choose the one you want."));
  785. break;
  786. case IDEC_REDEFINELINE:
  787. _tcscpy(str, _T("Draw a line from the callout to the corresponding device control by left clicking to add points. Right click to place the last point."));
  788. break;
  789. case IDEC_MOVECALLOUT:
  790. _tcscpy(str, _T("Move the entire callout around with the mouse and left click to place it."));
  791. break;
  792. case IDEC_MOVEOVERLAY:
  793. _tcscpy(str, _T("Move the overlay image around with the mouse and left click to place it."));
  794. break;
  795. }
  796. // set state indication if the string was actually filled
  797. if (_tcslen(str) > 0)
  798. m_ui.SetStateIndication(str);
  799. }
  800. void CDeviceView::StateEvent(POINT point, BOOL bClick, BOOL bLeft, WPARAM nKeyState)
  801. {
  802. // constrain point to view
  803. SIZE size = GetClientSize();
  804. const int WRAPAROUND = 10000;
  805. if (point.x < 0 || point.x > WRAPAROUND)
  806. point.x = 0;
  807. if (point.y < 0 || point.y > WRAPAROUND)
  808. point.y = 0;
  809. if (point.x >= size.cx)
  810. point.x = size.cx - 1;
  811. if (point.y >= size.cy)
  812. point.y = size.cy - 1;
  813. switch (m_State)
  814. {
  815. case IDEC_REDEFINECALLOUTMAX:
  816. if (m_pControlContext)
  817. m_pControlContext->PlaceCalloutMaxCorner(m_SubState, point);
  818. if (bClick && bLeft)
  819. {
  820. m_SubState++;
  821. if (m_SubState == 2)
  822. EndState();
  823. }
  824. break;
  825. case IDEC_REALIGNCALLOUT:
  826. if (m_pControlContext)
  827. m_pControlContext->ConsiderAlignment(point);
  828. if (bClick && bLeft)
  829. {
  830. if (m_pControlContext)
  831. m_pControlContext->FinalizeAlignment();
  832. EndState();
  833. }
  834. break;
  835. case IDEC_REDEFINELINE:
  836. if (m_pControlContext)
  837. m_pControlContext->SetLastLinePoint(m_SubState, point, (BOOL)(nKeyState & MK_SHIFT));
  838. if (bClick)
  839. {
  840. if (bLeft && m_pControlContext)
  841. m_SubState = m_pControlContext->GetNextLinePointIndex();
  842. if (!bLeft || m_pControlContext->ReachedMaxLinePoints())
  843. EndState();
  844. }
  845. break;
  846. case IDEC_MOVECALLOUT:
  847. if (m_pControlContext)
  848. m_pControlContext->Position(point);
  849. if (bClick && bLeft)
  850. EndState();
  851. break;
  852. case IDEC_MOVEOVERLAY:
  853. if (m_pControlContext)
  854. {
  855. if (!m_pControlContext->HasOverlay())
  856. EndState();
  857. else
  858. m_pControlContext->PositionOverlay(point);
  859. }
  860. if (bClick && bLeft)
  861. EndState();
  862. break;
  863. default:
  864. assert(0);
  865. }
  866. IndicateState();
  867. }
  868. void CDeviceView::EndState()
  869. {
  870. switch (m_SuperState)
  871. {
  872. case IDEC_NEWCALLOUT:
  873. switch (m_State)
  874. {
  875. case IDEC_REDEFINECALLOUTMAX:
  876. SetEditState(IDEC_REALIGNCALLOUT);
  877. break;
  878. case IDEC_REALIGNCALLOUT:
  879. SetEditState(IDEC_REDEFINELINE);
  880. break;
  881. case IDEC_REDEFINELINE:
  882. if (m_pControlContext)
  883. {
  884. m_pControlContext->SelectControl();
  885. m_pControlContext->SelectOverlay();
  886. if (m_pControlContext->HasOverlay())
  887. SetEditState(IDEC_MOVEOVERLAY);
  888. else
  889. EndEditState();
  890. }
  891. break;
  892. case IDEC_MOVEOVERLAY:
  893. EndEditState();
  894. break;
  895. default:
  896. assert(0);
  897. break;
  898. }
  899. break;
  900. case 0:
  901. EndEditState();
  902. break;
  903. default:
  904. assert(0);
  905. break;
  906. }
  907. }
  908. #endif
  909. //@@END_MSINTERNAL
  910. BOOL CDeviceView::DoesCalloutExistForOffset(DWORD dwOfs)
  911. {
  912. return DoesCalloutOtherThanSpecifiedExistForOffset(NULL, dwOfs);
  913. }
  914. BOOL CDeviceView::DoesCalloutOtherThanSpecifiedExistForOffset(CDeviceControl *pOther, DWORD dwOfs)
  915. {
  916. int nc = GetNumControls();
  917. for (int i = 0; i < nc; i++)
  918. {
  919. CDeviceControl *pControl = GetControl(i);
  920. if (pControl == NULL || pControl == pOther)
  921. continue;
  922. if (!pControl->IsOffsetAssigned())
  923. continue;
  924. if (pControl->GetOffset() == dwOfs)
  925. return TRUE;
  926. }
  927. return FALSE;
  928. }
  929. // This function returns the index of a control with the specified offset
  930. int CDeviceView::GetIndexFromOfs(DWORD dwOfs)
  931. {
  932. for (int i = 0; i < GetNumControls(); ++i)
  933. if (m_arpControl[i]->GetOffset() == dwOfs)
  934. return i;
  935. return -1;
  936. }
  937. //@@BEGIN_MSINTERNAL
  938. #ifdef DDKBUILD
  939. BOOL CDeviceView::WriteToINI()
  940. {
  941. // This function simply routes the call to the parent UI because the entire device info must
  942. // be saved, not just current view.
  943. return m_ui.WriteToINI();
  944. }
  945. #endif
  946. //@@END_MSINTERNAL
  947. int CDeviceView::GetViewIndex()
  948. {
  949. return m_ui.GetViewIndex(this);
  950. }
  951. //@@BEGIN_MSINTERNAL
  952. #ifdef DDKBUILD
  953. void CDeviceView::SelectImages()
  954. {
  955. LPCTSTR file = GetOpenFileName(
  956. g_hModule,
  957. m_hWnd,
  958. _T("Select An Image for This View"),
  959. _T("PNG Files (*.png)\0*.png\0All Files (*.*)\0*.*\0"),
  960. _T("png"));
  961. if (file == NULL)
  962. return;
  963. ManualLoadImage(file);
  964. }
  965. void CDeviceView::ManualLoadImage(LPCTSTR tszPath)
  966. {
  967. if (!tszPath)
  968. FormattedErrorBox(g_hModule, m_hWnd, IDS_TITLE_NOLOADVIEWIMAGE, IDS_NULLPATH);
  969. LPDIRECT3DSURFACE8 pSurf = m_ui.m_uig.GetSurface3D(); // GetSurface3D() calls AddRef() on the surface.
  970. CBitmap *pbmNewImage = CBitmap::CreateViaD3DX(tszPath, pSurf);
  971. if (pSurf)
  972. {
  973. // Release surface instance after we are done with it so we don't leak memory.
  974. pSurf->Release();
  975. pSurf = NULL;
  976. }
  977. if (pbmNewImage == NULL)
  978. {
  979. FormattedErrorBox(g_hModule, m_hWnd, IDS_TITLE_NOLOADVIEWIMAGE, IDS_COULDNOTCREATEIMAGEFROMFILE, tszPath);
  980. return;
  981. }
  982. // unpopulate only this view's stuff, not the callouts
  983. Unpopulate(TRUE);
  984. // replace
  985. m_pbmImage = pbmNewImage;
  986. pbmNewImage = NULL;
  987. MakeMissingImages();
  988. m_ptszImagePath = _tcsdup(tszPath);
  989. // redraw
  990. Invalidate();
  991. }
  992. #endif
  993. //@@END_MSINTERNAL
  994. BOOL CDeviceView::IsUnassignedOffsetAvailable()
  995. {
  996. DIDEVOBJSTRUCT os;
  997. HRESULT hr = FillDIDeviceObjectStruct(os, m_ui.m_lpDID);
  998. if (FAILED(hr))
  999. return FALSE;
  1000. if (os.nObjects < 1)
  1001. return FALSE;
  1002. assert(os.pdoi);
  1003. if (!os.pdoi)
  1004. return FALSE;
  1005. for (int i = 0; i < os.nObjects; i++)
  1006. {
  1007. const DIDEVICEOBJECTINSTANCEW &o = os.pdoi[i];
  1008. if (!DoesCalloutExistForOffset(o.dwOfs))
  1009. return TRUE;
  1010. }
  1011. return FALSE;
  1012. }
  1013. CDeviceViewText *CDeviceView::AddText(
  1014. HFONT f, COLORREF t, COLORREF b, const RECT &r, LPCTSTR text)
  1015. {
  1016. CDeviceViewText *pText = NewText();
  1017. if (!pText)
  1018. return NULL;
  1019. pText->SetLook(f, t, b);
  1020. pText->SetRect(r);
  1021. pText->SetText(text);
  1022. return pText;
  1023. }
  1024. CDeviceViewText *CDeviceView::AddText(
  1025. HFONT f, COLORREF t, COLORREF b, const POINT &p, LPCTSTR text)
  1026. {
  1027. CDeviceViewText *pText = NewText();
  1028. if (!pText)
  1029. return NULL;
  1030. pText->SetLook(f, t, b);
  1031. pText->SetPosition(p);
  1032. pText->SetTextAndResizeTo(text);
  1033. return pText;
  1034. }
  1035. CDeviceViewText *CDeviceView::AddWrappedLineOfText(
  1036. HFONT f, COLORREF t, COLORREF b, LPCTSTR text)
  1037. {
  1038. CDeviceViewText *pText = NewText();
  1039. if (!pText)
  1040. return NULL;
  1041. pText->SetLook(f, t, b);
  1042. pText->SetPosition(m_ptNextWLOText);
  1043. pText->SetTextAndResizeToWrapped(text);
  1044. m_ptNextWLOText.y += pText->GetHeight();
  1045. return pText;
  1046. }
  1047. CDeviceViewText *CDeviceView::NewText()
  1048. {
  1049. CDeviceViewText *pText = new CDeviceViewText(m_ui, *this);
  1050. if (!pText)
  1051. return NULL;
  1052. m_arpText.SetAtGrow(m_arpText.GetSize(), pText);
  1053. return pText;
  1054. }
  1055. // Called by PopulateListView(), after the CDeviceViewText and CDeviceControl lists are constructed.
  1056. // Returns TRUE if any label is printed with ellipses (not enough space).
  1057. BOOL CDeviceView::CalculateHeaderRect()
  1058. {
  1059. TCHAR tszHeader[MAX_PATH];
  1060. // Control column
  1061. //@@BEGIN_MSINTERNAL
  1062. #ifdef DDKBUILD
  1063. if (m_arpText.GetSize() > 2)
  1064. /*
  1065. //@@END_MSINTERNAL
  1066. if (m_arpText.GetSize())
  1067. //@@BEGIN_MSINTERNAL
  1068. */
  1069. #endif
  1070. //@@END_MSINTERNAL
  1071. {
  1072. HDC hDC = CreateCompatibleDC(NULL);
  1073. if (hDC)
  1074. {
  1075. CPaintHelper ph(m_ui.m_uig, hDC);
  1076. ph.SetElement(UIE_CALLOUT);
  1077. for (int i = 0; i < 2; i++)
  1078. {
  1079. // Check if there are two columns, break out the 2nd iteration if not 2 columns.
  1080. if (i == 1 && !(GetNumControls() > 1 &&
  1081. m_arpControl[0]->GetCalloutMaxRect().top == m_arpControl[1]->GetCalloutMaxRect().top))
  1082. break;
  1083. RECT rcheader;
  1084. if (m_arpText.GetSize())
  1085. {
  1086. // Action column
  1087. rcheader = m_arpText[i]->GetRect();
  1088. rcheader.bottom -= rcheader.top;
  1089. rcheader.top = 0;
  1090. if (i == 0)
  1091. rcheader.left = 0;
  1092. else
  1093. rcheader.left = (g_ViewRect.right - g_ViewRect.left) >> 1;
  1094. m_HeaderRectControl[i] = rcheader;
  1095. // Find out if the control header label will be clipped.
  1096. LoadString(g_hModule, IDS_LISTHEADER_CTRL, tszHeader, MAX_PATH);
  1097. DrawText(hDC, tszHeader, -1, &rcheader, DT_LEFT|DT_NOPREFIX|DT_CALCRECT);
  1098. if (rcheader.right > m_HeaderRectControl[i].right || rcheader.bottom > m_HeaderRectControl[i].bottom)
  1099. m_bControlHeaderClipped = TRUE;
  1100. // Control column
  1101. rcheader = m_arpControl[i]->GetCalloutMaxRect();
  1102. rcheader.bottom -= rcheader.top;
  1103. rcheader.top = 0;
  1104. m_HeaderRectAction[i] = rcheader;
  1105. // Find out if the action header label will be clipped.
  1106. LoadString(g_hModule, IDS_LISTHEADER_ACTION, tszHeader, MAX_PATH);
  1107. DrawText(hDC, tszHeader, -1, &rcheader, DT_LEFT|DT_NOPREFIX|DT_CALCRECT);
  1108. if (rcheader.right > m_HeaderRectAction[i].right || rcheader.bottom > m_HeaderRectAction[i].bottom)
  1109. m_bActionHeaderClipped = TRUE;
  1110. }
  1111. }
  1112. }
  1113. DeleteDC(hDC);
  1114. }
  1115. return m_bActionHeaderClipped || m_bControlHeaderClipped;
  1116. }
  1117. int CDeviceView::GetNumTexts()
  1118. {
  1119. return m_arpText.GetSize();
  1120. }
  1121. CDeviceViewText *CDeviceView::GetText(int nText)
  1122. {
  1123. if (nText < 0 || nText >= GetNumTexts())
  1124. return NULL;
  1125. return m_arpText[nText];
  1126. }
  1127. void CDeviceView::SetImage(CBitmap *&refpbm)
  1128. {
  1129. delete m_pbmImage;
  1130. m_pbmImage = refpbm;
  1131. refpbm = NULL;
  1132. MakeMissingImages();
  1133. Invalidate();
  1134. }
  1135. void CDeviceView::SetImagePath(LPCTSTR tszPath)
  1136. {
  1137. if (m_ptszImagePath)
  1138. free(m_ptszImagePath);
  1139. m_ptszImagePath = NULL;
  1140. if (tszPath)
  1141. m_ptszImagePath = _tcsdup(tszPath);
  1142. }
  1143. void CDeviceView::CalcDimensions()
  1144. {
  1145. // go through all texts and controls to find the max y coord
  1146. int max = g_sizeImage.cy - g_iListHeaderHeight;
  1147. int i = 0;
  1148. for (; i < GetNumTexts(); i++)
  1149. {
  1150. CDeviceViewText *pText = GetText(i);
  1151. if (!pText)
  1152. continue;
  1153. int ty = pText->GetMaxY();
  1154. if (ty > max)
  1155. max = ty;
  1156. }
  1157. for (i = 0; i < GetNumControls(); i++)
  1158. {
  1159. CDeviceControl *pControl = GetControl(i);
  1160. if (!pControl)
  1161. continue;
  1162. int cy = pControl->GetMaxY();
  1163. if (cy > max)
  1164. max = cy;
  1165. }
  1166. // set
  1167. m_nViewHeight = max;
  1168. m_nScrollOffset = 0;
  1169. // enable scrollbar if view height more than window size
  1170. if (m_nViewHeight > g_sizeImage.cy - g_iListHeaderHeight)
  1171. EnableScrollBar();
  1172. }
  1173. void CDeviceView::DisableScrollBar()
  1174. {
  1175. if (!m_sb.m_hWnd)
  1176. return;
  1177. m_sb.Destroy();
  1178. }
  1179. void CDeviceView::EnableScrollBar()
  1180. {
  1181. if (m_sb.m_hWnd)
  1182. return;
  1183. FLEXSCROLLBARCREATESTRUCT cs;
  1184. cs.dwSize = sizeof(cs);
  1185. cs.dwFlags = FSBF_VERT;
  1186. cs.min = 0;
  1187. cs.max = m_nViewHeight;
  1188. cs.page = g_sizeImage.cy - g_iListHeaderHeight;
  1189. cs.pos = m_nScrollOffset;
  1190. cs.hWndParent = m_hWnd;
  1191. cs.hWndNotify = m_hWnd;
  1192. RECT rect = {g_sizeImage.cx - DEFAULTVIEWSBWIDTH, g_iListHeaderHeight, g_sizeImage.cx, g_sizeImage.cy};
  1193. cs.rect = rect;
  1194. cs.bVisible = TRUE;
  1195. m_sb.SetColors(
  1196. m_ui.m_uig.GetBrushColor(UIE_SBTRACK),
  1197. m_ui.m_uig.GetBrushColor(UIE_SBTHUMB),
  1198. m_ui.m_uig.GetPenColor(UIE_SBBUTTON));
  1199. m_sb.Create(&cs);
  1200. }
  1201. LRESULT CDeviceView::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  1202. {
  1203. switch (msg)
  1204. {
  1205. case WM_PAINT:
  1206. m_bForcePaint = TRUE;
  1207. return CFlexWnd::WndProc(hWnd, msg, wParam, lParam);
  1208. case WM_FLEXVSCROLL:
  1209. {
  1210. int code = (int)wParam;
  1211. CFlexScrollBar *pSB = (CFlexScrollBar *)lParam;
  1212. if (!pSB)
  1213. return 0;
  1214. int nLine = 5;
  1215. int nPage = MulDiv(pSB->GetPage(), 9, 10);
  1216. switch (code)
  1217. {
  1218. case SB_LINEUP: pSB->AdjustPos(-nLine); break;
  1219. case SB_LINEDOWN: pSB->AdjustPos(nLine); break;
  1220. case SB_PAGEUP: pSB->AdjustPos(-nPage); break;
  1221. case SB_PAGEDOWN: pSB->AdjustPos(nPage); break;
  1222. case SB_THUMBTRACK: pSB->SetPos(pSB->GetThumbPos()); break;
  1223. }
  1224. m_nScrollOffset = pSB->GetPos();
  1225. Invalidate();
  1226. return 0;
  1227. }
  1228. case WM_FLEXHSCROLL:
  1229. assert(0);
  1230. default:
  1231. return CFlexWnd::WndProc(hWnd, msg, wParam, lParam);
  1232. }
  1233. }
  1234. void CDeviceView::ScrollToMakeControlVisible(const RECT &rc)
  1235. {
  1236. RECT viewrc;
  1237. if (!m_bScrollEnable)
  1238. return;
  1239. GetClientRect(&viewrc);
  1240. viewrc.bottom -= g_iListHeaderHeight;
  1241. viewrc.top += m_nScrollOffset;
  1242. viewrc.bottom += m_nScrollOffset;
  1243. // If scroll enabled, we scroll the view to make the control visible if not already so.
  1244. if (m_bScrollEnable && m_sb.m_hWnd &&
  1245. !(viewrc.left <= rc.left &&
  1246. viewrc.right >= rc.right &&
  1247. viewrc.top <= rc.top &&
  1248. viewrc.bottom >= rc.bottom))
  1249. {
  1250. // If the callout is below the view window, scroll so it shows up at the bottom of the window.
  1251. if (viewrc.bottom < rc.bottom)
  1252. m_sb.SetPos(m_sb.GetPos() + rc.bottom - viewrc.bottom);
  1253. else
  1254. m_sb.SetPos(rc.top);
  1255. m_nScrollOffset = m_sb.GetPos();
  1256. Invalidate();
  1257. }
  1258. }
  1259. void CDeviceView::SwapControls(int i, int j)
  1260. {
  1261. RECT rect;
  1262. CDeviceControl *pTmpControl;
  1263. CDeviceViewText *pTmpViewText;
  1264. pTmpControl = m_arpControl[i];
  1265. m_arpControl[i] = m_arpControl[j];
  1266. m_arpControl[j] = pTmpControl;
  1267. pTmpViewText = m_arpText[i];
  1268. m_arpText[i] = m_arpText[j];
  1269. m_arpText[j] = pTmpViewText;
  1270. // Swap the rect back so everything will display properly.
  1271. rect = m_arpControl[i]->GetCalloutMaxRect();
  1272. m_arpControl[i]->SetCalloutMaxRect(m_arpControl[j]->GetCalloutMaxRect());
  1273. m_arpControl[j]->SetCalloutMaxRect(rect);
  1274. rect = m_arpText[i]->GetRect();
  1275. m_arpText[i]->SetRect(m_arpText[j]->GetRect());
  1276. m_arpText[j]->SetRect(rect);
  1277. // Exchange the text rect width, so the correct width stays with the correct text.
  1278. RECT rc1 = m_arpText[i]->GetRect();
  1279. RECT rc2 = m_arpText[j]->GetRect();
  1280. // Store rc1's new width first
  1281. int iTempWidth = rc1.right - (rc2.right - rc2.left);
  1282. rc2.left = rc2.right - (rc1.right - rc1.left); // Adjust rc2's width
  1283. rc1.left = iTempWidth; // Adjust rc1's width
  1284. m_arpText[i]->SetRect(rc1);
  1285. m_arpText[j]->SetRect(rc2);
  1286. }
  1287. // Implements a simple selection sort algorithm to sort the control array and viewtext array.
  1288. // - iStart is the starting index, inclusive.
  1289. // - iEnd is the last index, exclusive.
  1290. void CDeviceView::SortCallouts(int iStart, int iEnd)
  1291. {
  1292. for (int i = iStart; i < iEnd - 1; ++i)
  1293. {
  1294. DWORD dwSmallestOfs = m_arpControl[i]->GetOffset();
  1295. int iSmallestIndex = i;
  1296. for (int j = i + 1; j < iEnd; ++j)
  1297. if (m_arpControl[j]->GetOffset() < dwSmallestOfs)
  1298. {
  1299. dwSmallestOfs = m_arpControl[j]->GetOffset();
  1300. iSmallestIndex = j;
  1301. }
  1302. // Swap the smallest element with i-th element.
  1303. if (iSmallestIndex != i)
  1304. SwapControls(i, iSmallestIndex);
  1305. }
  1306. }
  1307. void CDeviceView::SortAssigned(BOOL bSort)
  1308. {
  1309. // If less than 2 controls, no need for sorting.
  1310. if (m_arpControl.GetSize() < 2)
  1311. return;
  1312. int iCalloutX[2] = {m_arpControl[0]->GetMinX(), m_arpControl[1]->GetMinX()}; // Callout X for the two columns
  1313. // Sort the text array and control array.
  1314. if (bSort)
  1315. {
  1316. // First move all the assigned controls to the first n elements.
  1317. int iNextAssignedWriteIndex = 0;
  1318. for (int i = 0; i < m_arpControl.GetSize(); ++i)
  1319. if (m_arpControl[i]->HasAction())
  1320. {
  1321. // Swap the controls
  1322. SwapControls(i, iNextAssignedWriteIndex);
  1323. ++iNextAssignedWriteIndex; // Increment the write index
  1324. }
  1325. // Sort the two parts now
  1326. SortCallouts(0, iNextAssignedWriteIndex);
  1327. SortCallouts(iNextAssignedWriteIndex, m_arpControl.GetSize());
  1328. } else
  1329. SortCallouts(0, m_arpControl.GetSize());
  1330. }
  1331. void CDeviceView::DoOnPaint(HDC hDC)
  1332. {
  1333. // Paint only if we have an update region.
  1334. if (GetUpdateRect(m_hWnd, NULL, FALSE) || m_bForcePaint)
  1335. OnPaint(hDC);
  1336. m_bForcePaint = FALSE;
  1337. }