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.

832 lines
19 KiB

  1. //-----------------------------------------------------------------------------
  2. // File: cdevicecontrol.cpp
  3. //
  4. // Desc: CDeviceControl is a class that encapsulate the functionality of a
  5. // device control (or a callout). CDeviceView accesses it to retrieve/
  6. // save information about the control.
  7. //
  8. // Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  9. //-----------------------------------------------------------------------------
  10. #include "common.hpp"
  11. CDeviceControl::CDeviceControl(CDeviceUI &ui, CDeviceView &view) :
  12. m_ui(ui),
  13. m_view(view),
  14. m_bHighlight(FALSE),
  15. m_ptszCaption(NULL),
  16. m_dwDrawTextFlags(0),
  17. m_FontHeight(-1),
  18. m_bCalledCalcCallout(FALSE),
  19. m_bPlacedOnlyFirstCorner(FALSE),
  20. m_bInit(FALSE),
  21. m_dwCalloutAlign(CAF_TOPLEFT),
  22. m_nLinePoints(0),
  23. m_dwDeviceControlOffset((DWORD)-1),
  24. m_bOffsetAssigned(FALSE),
  25. m_pbmOverlay(NULL),
  26. m_pbmHitMask(NULL),
  27. m_ptszOverlayPath(NULL),
  28. m_bCaptionClipped(FALSE)
  29. {
  30. }
  31. CDeviceControl::~CDeviceControl()
  32. {
  33. DEVICEUINOTIFY uin;
  34. uin.from = DEVUINFROM_CONTROL;
  35. uin.control.pControl = (CDeviceControl *)this;
  36. uin.msg = DEVUINM_ONCONTROLDESTROY;
  37. m_ui.Notify(uin);
  38. if (m_ptszCaption)
  39. free(m_ptszCaption);
  40. delete m_pbmOverlay;
  41. delete m_ptszOverlayPath;
  42. }
  43. void CDeviceControl::SetCaption(LPCTSTR tszCaption, BOOL bFixed)
  44. {
  45. LPTSTR tszNewCaption = NULL;
  46. m_bFixed = bFixed;
  47. if (tszCaption != NULL)
  48. {
  49. tszNewCaption = _tcsdup(tszCaption);
  50. if (tszNewCaption == NULL)
  51. return;
  52. }
  53. free(m_ptszCaption);
  54. m_ptszCaption = tszNewCaption;
  55. tszNewCaption = NULL;
  56. CalcCallout();
  57. Invalidate();
  58. }
  59. LPCTSTR CDeviceControl::GetCaption()
  60. {
  61. return (LPCTSTR)m_ptszCaption;
  62. }
  63. BOOL CDeviceControl::HitControl(POINT point)
  64. {
  65. return FALSE;
  66. }
  67. DEVCTRLHITRESULT CDeviceControl::HitTest(POINT test)
  68. {
  69. if (!m_bInit)
  70. return DCHT_NOHIT;
  71. if (m_ui.InEditMode() &&
  72. PtInRect(&m_rectCalloutMax, test))
  73. return DCHT_MAXRECT;
  74. PrepCallout();
  75. if (PtInRect(&m_rectCallout, test))
  76. return DCHT_CAPTION;
  77. if (HitControl(test))
  78. return DCHT_CONTROL;
  79. return DCHT_NOHIT;
  80. }
  81. void CDeviceControl::Init()
  82. {
  83. m_uin.from = DEVUINFROM_CONTROL;
  84. m_uin.control.pControl = this;
  85. CalcCallout();
  86. m_bInit = TRUE;
  87. }
  88. // We will have to know the view's scrolling offset to adjust the tooltip's position.
  89. void CDeviceControl::OnMouseOver(POINT point)
  90. {
  91. // Tooltip only if the callout text is clipped.
  92. if (m_bCaptionClipped)
  93. {
  94. TOOLTIPINITPARAM ttip;
  95. ttip.hWndParent = GetParent(m_view.m_hWnd); // Parent is the page window.
  96. ttip.iSBWidth = 0;
  97. ttip.dwID = m_dwDeviceControlOffset;
  98. ttip.hWndNotify = m_view.m_hWnd;
  99. ttip.tszCaption = GetCaption();
  100. CFlexToolTip::UpdateToolTipParam(ttip);
  101. } else
  102. CFlexWnd::s_ToolTip.SetToolTipParent(NULL);
  103. m_uin.msg = DEVUINM_MOUSEOVER;
  104. m_ui.Notify(m_uin);
  105. }
  106. void CDeviceControl::OnClick(POINT point, BOOL bLeft, BOOL bDoubleClick)
  107. {
  108. //@@BEGIN_MSINTERNAL
  109. #ifdef DDKBUILD
  110. if (!bLeft && m_ui.InEditMode())
  111. {
  112. // If right click in edit mode, pop up the edit menu.
  113. m_view.EditMenu(point, this);
  114. return;
  115. }
  116. #endif
  117. //@@END_MSINTERNAL
  118. // If this control is not assigned, and we are in view mode, we should not do anything (highlight).
  119. if (!lstrcmp(m_ptszCaption, g_tszUnassignedControlCaption) && !m_ui.m_uig.InEditMode())
  120. return;
  121. m_uin.msg = bDoubleClick ? DEVUINM_DOUBLECLICK : DEVUINM_CLICK;
  122. m_uin.click.bLeftButton = bLeft;
  123. m_ui.Notify(m_uin);
  124. }
  125. void CDeviceControl::Unpopulate()
  126. {
  127. }
  128. void CDeviceControl::Highlight(BOOL bHighlight)
  129. {
  130. if (m_bHighlight == bHighlight)
  131. return;
  132. // If the callout text is the default text, no action is assigned, and we don't highlight it.
  133. //@@BEGIN_MSINTERNAL
  134. // ISSUE-2000/12/21-MarcAnd This breaks highlighting of unassigned controls
  135. // When you're trying to assign
  136. //@@END_MSINTERNAL
  137. if (!lstrcmp(m_ptszCaption, g_tszUnassignedControlCaption) && bHighlight && !m_ui.m_uig.InEditMode())
  138. return;
  139. m_bHighlight = bHighlight;
  140. // If the view has scrolling enabled, we need to adjust the scroll
  141. // bar position to make this callout visible.
  142. if (bHighlight)
  143. m_view.ScrollToMakeControlVisible(m_rectCalloutMax);
  144. CalcCallout();
  145. // We do not invalidate rectangle if we are unhighlighting. Let CDeviceView handle that.
  146. if (bHighlight) Invalidate();
  147. }
  148. void CDeviceControl::GetInfo(GUID &rGuid, DWORD &rdwOffset)
  149. {
  150. m_ui.GetDeviceInstanceGuid(rGuid);
  151. rdwOffset = m_dwDeviceControlOffset;
  152. }
  153. BOOL CDeviceControl::PrepCaption()
  154. {
  155. if (m_ptszCaption != NULL)
  156. return TRUE;
  157. m_ptszCaption = _tcsdup(g_tszUnassignedControlCaption);
  158. return m_ptszCaption != NULL;
  159. }
  160. void CDeviceControl::PrepLinePoints()
  161. {
  162. if (m_nLinePoints > 0)
  163. return;
  164. m_nLinePoints = 1;
  165. POINT pt = {0, 0};
  166. if (m_dwCalloutAlign & CAF_LEFT)
  167. pt.x = m_rectCalloutMax.left;
  168. if (m_dwCalloutAlign & CAF_RIGHT)
  169. pt.x = m_rectCalloutMax.right - 1;
  170. if (m_dwCalloutAlign & CAF_TOP)
  171. pt.y = m_rectCalloutMax.top;
  172. if (m_dwCalloutAlign & CAF_BOTTOM)
  173. pt.y = m_rectCalloutMax.bottom - 1;
  174. if (!(m_dwCalloutAlign & (CAF_LEFT | CAF_RIGHT)))
  175. pt.x = (m_rectCalloutMax.left + m_rectCalloutMax.right - 1) / 2;
  176. if (!(m_dwCalloutAlign & (CAF_BOTTOM | CAF_TOP)))
  177. pt.y = (m_rectCalloutMax.top + m_rectCalloutMax.bottom - 1) / 2;
  178. m_rgptLinePoint[0] = pt;
  179. }
  180. void CDeviceControl::PrepCallout()
  181. {
  182. if (m_bCalledCalcCallout)
  183. return;
  184. CalcCallout();
  185. }
  186. void CDeviceControl::PrepFont()
  187. {
  188. if (m_FontHeight != -1)
  189. return;
  190. HDC hDC = CreateCompatibleDC(NULL);
  191. if (hDC != NULL)
  192. {
  193. RECT rect = {0, 0, 500, 1};
  194. {
  195. CPaintHelper ph(m_ui.m_uig, hDC);
  196. ph.SetFont(UIF_CALLOUT);
  197. m_FontHeight = DrawText(hDC, _T("Testify"), -1, &rect, m_dwDrawTextFlags);
  198. }
  199. DeleteDC(hDC);
  200. }
  201. }
  202. void CDeviceControl::CalcCallout()
  203. {
  204. m_bCalledCalcCallout = TRUE;
  205. RECT max = m_rectCalloutMax;
  206. InflateRect(&max, -1, -1);
  207. RECT rect = max;
  208. rect.bottom = rect.top + 1;
  209. PrepFont();
  210. HDC hDC = CreateCompatibleDC(NULL);
  211. {
  212. CPaintHelper ph(m_ui.m_uig, hDC);
  213. ph.SetFont(UIF_CALLOUT);
  214. // We make sure the max rect height is at least same as the font requires.
  215. m_dwDrawTextFlags = DT_SINGLELINE | DT_CALCRECT | DT_NOPREFIX | DT_END_ELLIPSIS | DT_EDITCONTROL;
  216. RECT hrect = rect;
  217. DrawText(hDC, m_ptszCaption, -1, &hrect, m_dwDrawTextFlags);
  218. if (hrect.bottom > max.bottom) max.bottom = hrect.bottom;
  219. m_dwDrawTextFlags = DT_WORDBREAK | DT_CALCRECT | DT_NOPREFIX | DT_END_ELLIPSIS | DT_EDITCONTROL;
  220. // first, drawtext/calcrect into the temporary rect
  221. if (!PrepCaption())
  222. {
  223. return;
  224. }
  225. int th = DrawText(hDC, m_ptszCaption, -1, &rect, m_dwDrawTextFlags);
  226. m_bCaptionClipped = rect.bottom > max.bottom || rect.right > max.right; // Set clipped flag.
  227. BOOL bSingleTextLine = th <= m_FontHeight;
  228. if (rect.right > max.right)
  229. {
  230. bSingleTextLine = TRUE;
  231. rect.right = max.right;
  232. }
  233. if (bSingleTextLine)
  234. m_dwDrawTextFlags &= ~DT_WORDBREAK;
  235. m_dwDrawTextFlags &= ~DT_CALCRECT;
  236. RECT rect2 = rect;
  237. if (rect2.bottom > max.bottom)
  238. rect2.bottom = max.bottom;
  239. th = DrawText(hDC, m_ptszCaption, -1, &rect2, m_dwDrawTextFlags);
  240. int ith = (th / m_FontHeight) * m_FontHeight;
  241. //@@BEGIN_MSINTERNAL
  242. //LTRACE(QSAFESTR(m_ptszCaption));
  243. //LTRACE(" max = %s", RECTDIMSTR(max));
  244. //LTRACE("!rect = %s", RECTDIMSTR(rect));
  245. //@@END_MSINTERNAL
  246. rect.bottom = rect.top + ith + 1;
  247. //@@BEGIN_MSINTERNAL
  248. //LTRACE(" rect = %s", RECTDIMSTR(rect));
  249. //LTRACE("rect2 = %s", RECTDIMSTR(rect2));
  250. //LTRACE("th = %d, ith = %d, m_FontHeight = %d", th, ith, m_FontHeight);
  251. //@@END_MSINTERNAL
  252. }
  253. DeleteDC(hDC);
  254. hDC = NULL;
  255. if (rect.bottom > max.bottom)
  256. rect.bottom = max.bottom;
  257. assert(rect.right <= max.right);
  258. assert(rect.bottom <= max.bottom);
  259. PrepLinePoints();
  260. POINT adj = {0, 0};
  261. assert(rect.left == max.left);
  262. assert(rect.top == max.top);
  263. int w = rect.right - rect.left;
  264. int h = rect.bottom - rect.top;
  265. int mw = max.right - max.left;
  266. int mh = max.bottom - max.top;
  267. int dw = mw - w, dh = mh - h;
  268. int cx = mw / 2 + max.left, cy = mh / 2 + max.top;
  269. int cl = cx - w / 2, ct = cy - h / 2;
  270. assert(dw >= 0);
  271. assert(dh >= 0);
  272. if (m_dwCalloutAlign & CAF_RIGHT && rect.right < max.right)
  273. adj.x = max.right - rect.right;
  274. if (m_dwCalloutAlign & CAF_BOTTOM && rect.bottom < max.bottom)
  275. adj.y = max.bottom - rect.bottom;
  276. if (!(m_dwCalloutAlign & (CAF_RIGHT | CAF_LEFT)) && w < mw && rect.left != cl)
  277. adj.x = cl - rect.left;
  278. if (!(m_dwCalloutAlign & (CAF_BOTTOM | CAF_TOP)) && h < mh && rect.top != ct)
  279. adj.y = ct - rect.top;
  280. OffsetRect(&rect, adj.x, adj.y);
  281. InflateRect(&rect, 1, 1);
  282. m_rectCallout = rect;
  283. }
  284. BOOL CDeviceControl::DrawOverlay(HDC hDC)
  285. {
  286. if (m_pbmOverlay == NULL)
  287. return FALSE;
  288. return m_pbmOverlay->Blend(hDC, m_ptOverlay);
  289. }
  290. void CDeviceControl::OnPaint(HDC hDC)
  291. {
  292. if (!m_bInit)
  293. return;
  294. // If we are in view mode and the callout is not assigned, don't draw anything.
  295. if (!m_ui.m_uig.InEditMode() && !lstrcmp(m_ptszCaption, g_tszUnassignedControlCaption))
  296. return;
  297. PrepCallout();
  298. CPaintHelper ph(m_ui.m_uig, hDC);
  299. UIELEMENT eCallout = m_bHighlight ? UIE_CALLOUTHIGH : UIE_CALLOUT;
  300. // draw lines...
  301. if (m_nLinePoints > 1)
  302. {
  303. ph.SetElement(UIE_CALLOUTSHADOW);
  304. PolyLineArrowShadow(hDC, m_rgptLinePoint, m_nLinePoints);
  305. ph.SetElement(eCallout);
  306. PolyLineArrow(hDC, m_rgptLinePoint, m_nLinePoints);
  307. }
  308. //@@BEGIN_MSINTERNAL
  309. #ifdef DDKBUILD
  310. // if we're in edit mode, show the callout max rect
  311. if (m_ui.InEditMode())
  312. {
  313. ph.SetElement(UIE_CALLOUTMAX);
  314. ph.Rectangle(m_rectCalloutMax);
  315. ph.SetElement(eCallout);
  316. ph.Rectangle(m_rectCallout);
  317. }
  318. // if we're in edit mode, indicate alignment
  319. if (m_ui.InEditMode())
  320. {
  321. ph.SetElement(UIE_CALLOUTALIGN);
  322. const int &align = m_dwCalloutAlign;
  323. const RECT &rect = m_rectCalloutMax;
  324. int vert = align & (CAF_TOP | CAF_BOTTOM);
  325. int horz = align & (CAF_LEFT | CAF_RIGHT);
  326. BOOL bHorz = TRUE;
  327. BOOL bVert = TRUE;
  328. int hsq, hy, heq, vsq, vx, veq, s, e;
  329. switch (vert)
  330. {
  331. case CAF_TOP:
  332. hy = rect.top;
  333. vsq = 0;
  334. veq = 1;
  335. break;
  336. case 0:
  337. bHorz = FALSE;
  338. vsq = 1;
  339. veq = 3;
  340. break;
  341. case CAF_BOTTOM:
  342. hy = rect.bottom - 1;
  343. vsq = 3;
  344. veq = 4;
  345. break;
  346. }
  347. switch (horz)
  348. {
  349. case CAF_LEFT:
  350. vx = rect.left;
  351. hsq = 0;
  352. heq = 1;
  353. break;
  354. case 0:
  355. bVert = FALSE;
  356. hsq = 1;
  357. heq = 3;
  358. break;
  359. case CAF_RIGHT:
  360. vx = rect.right - 1;
  361. hsq = 3;
  362. heq = 4;
  363. break;
  364. }
  365. if (bHorz)
  366. {
  367. s = ConvertVal(hsq, 0, 4, rect.left, rect.right - 1);
  368. e = ConvertVal(heq, 0, 4, rect.left, rect.right - 1);
  369. MoveToEx(hDC, s, hy, NULL);
  370. LineTo(hDC, e + 1, hy);
  371. }
  372. if (bVert)
  373. {
  374. s = ConvertVal(vsq, 0, 4, rect.top, rect.bottom - 1);
  375. e = ConvertVal(veq, 0, 4, rect.top, rect.bottom - 1);
  376. MoveToEx(hDC, vx, s, NULL);
  377. LineTo(hDC, vx, e + 1);
  378. }
  379. }
  380. #endif
  381. //@@END_MSINTERNAL
  382. // draw text
  383. ph.SetElement(eCallout);
  384. RECT rect = m_rectCallout;
  385. InflateRect(&rect, -1, -1);
  386. // If this control is assigned an action with DIA_FIXED (m_bFixed), use gray color for text.
  387. COLORREF OldColor;
  388. if (m_bFixed)
  389. {
  390. OldColor = ::SetTextColor(hDC, 0); // Set an arbitrary color to find out what we are currently using.
  391. ::SetTextColor(hDC, RGB(GetRValue(OldColor) >> 1, GetGValue(OldColor) >> 1, GetBValue(OldColor) >> 1));
  392. }
  393. if (m_ptszCaption)
  394. DrawText(hDC, m_ptszCaption, -1, &rect, m_dwDrawTextFlags);
  395. if (m_bFixed)
  396. ::SetTextColor(hDC, OldColor);
  397. }
  398. void CDeviceControl::Invalidate()
  399. {
  400. m_view.Invalidate();
  401. }
  402. void MakeRect(RECT &rect, POINT a, POINT b)
  403. {
  404. rect.left = min(a.x, b.x);
  405. rect.right = max(a.x, b.x);
  406. rect.top = min(a.y, b.y);
  407. rect.bottom = max(a.y, b.y);
  408. }
  409. void CDeviceControl::PlaceCalloutMaxCorner(int nCorner, POINT point)
  410. {
  411. switch (nCorner)
  412. {
  413. case 0:
  414. m_ptFirstCorner = point;
  415. m_bPlacedOnlyFirstCorner = TRUE;
  416. Invalidate();
  417. break;
  418. case 1:
  419. MakeRect(m_rectCalloutMax, m_ptFirstCorner, point);
  420. m_bPlacedOnlyFirstCorner = FALSE;
  421. if (!m_bInit)
  422. Init();
  423. else
  424. CalcCallout();
  425. Invalidate();
  426. break;
  427. default:
  428. assert(0);
  429. break;
  430. }
  431. }
  432. void CDeviceControl::SetLastLinePoint(int nPoint, POINT point, BOOL bShiftDown)
  433. {
  434. if (!(nPoint >= 0 && nPoint < MAX_DEVICECONTROL_LINEPOINTS))
  435. return;
  436. // Check for SHIFT key state
  437. if (nPoint && bShiftDown) // SHIFT key only makes a difference if we are setting 2nd and subsequent points.
  438. {
  439. // SHIFT key down. Need to draw controlled line.
  440. if (labs(m_rgptLinePoint[nPoint-1].x - point.x) > labs(m_rgptLinePoint[nPoint-1].y - point.y))
  441. {
  442. // Wider. Draw horizontal.
  443. m_rgptLinePoint[nPoint].x = point.x;
  444. m_rgptLinePoint[nPoint].y = m_rgptLinePoint[nPoint-1].y;
  445. } else
  446. {
  447. // Taller. Draw vertical
  448. m_rgptLinePoint[nPoint].x = m_rgptLinePoint[nPoint-1].x;
  449. m_rgptLinePoint[nPoint].y = point.y;
  450. }
  451. } else
  452. m_rgptLinePoint[nPoint] = point; // SHIFT key not down. Draw line as usual.
  453. m_nLinePoints = nPoint + 1;
  454. Invalidate();
  455. if (m_nLinePoints < 2)
  456. return;
  457. POINT prev = m_rgptLinePoint[m_nLinePoints - 2];
  458. // remove identical points
  459. if (point.x == prev.x && point.y == prev.y)
  460. {
  461. m_nLinePoints--;
  462. return;
  463. }
  464. //@@BEGIN_MSINTERNAL
  465. // TODO: remove the midpoint of colinear triples
  466. //@@END_MSINTERNAL
  467. }
  468. void PlaceRectCenter(RECT &rect, POINT point)
  469. {
  470. POINT center = {
  471. (rect.left + rect.right) / 2,
  472. (rect.top + rect.bottom) / 2};
  473. OffsetRect(&rect, point.x - center.x, point.y - center.y);
  474. }
  475. void OffsetRectToWithin(RECT &rect, const RECT &bounds)
  476. {
  477. POINT adj = {0, 0};
  478. if (rect.left < bounds.left)
  479. adj.x = bounds.left - rect.left;
  480. if (rect.right > bounds.right)
  481. adj.x = bounds.right - rect.right;
  482. if (rect.top < bounds.top)
  483. adj.y = bounds.top - rect.top;
  484. if (rect.bottom > bounds.bottom)
  485. adj.y = bounds.bottom - rect.bottom;
  486. OffsetRect(&rect, adj.x, adj.y);
  487. }
  488. void CDeviceControl::Position(POINT point)
  489. {
  490. PlaceRectCenter(m_rectCalloutMax, point);
  491. RECT client;
  492. m_view.GetClientRect(&client);
  493. OffsetRectToWithin(m_rectCalloutMax, client);
  494. CalcCallout();
  495. Invalidate();
  496. }
  497. void CDeviceControl::ConsiderAlignment(POINT point)
  498. {
  499. POINT center = {
  500. (m_rectCalloutMax.right + m_rectCalloutMax.left) / 2,
  501. (m_rectCalloutMax.bottom + m_rectCalloutMax.top) / 2};
  502. SIZE dim = {
  503. m_rectCalloutMax.right - m_rectCalloutMax.left,
  504. m_rectCalloutMax.bottom - m_rectCalloutMax.top};
  505. SIZE delta = {point.x - center.x, point.y - center.y};
  506. int MININ = m_FontHeight;
  507. SIZE in = {max(dim.cx / 4, MININ), max(dim.cy / 4, MININ)};
  508. DWORD align = 0;
  509. if (delta.cx < -in.cx)
  510. align |= CAF_LEFT;
  511. if (delta.cx > in.cx)
  512. align |= CAF_RIGHT;
  513. if (delta.cy < -in.cy)
  514. align |= CAF_TOP;
  515. if (delta.cy > in.cy)
  516. align |= CAF_BOTTOM;
  517. m_dwCalloutAlign = align;
  518. CalcCallout();
  519. Invalidate();
  520. }
  521. //@@BEGIN_MSINTERNAL
  522. #ifdef DDKBUILD
  523. void CDeviceControl::ReselectControl()
  524. {
  525. SelectControl(TRUE);
  526. }
  527. void CDeviceControl::SelectControl(BOOL bReselect)
  528. {
  529. CSelControlDlg dlg(m_view, *this, bReselect, m_dwDeviceControlOffset, m_ui.m_didi);
  530. switch (dlg.DoModal(m_view.m_hWnd))
  531. {
  532. case SCDR_OK:
  533. m_dwDeviceControlOffset = dlg.GetOffset();
  534. m_bOffsetAssigned = TRUE;
  535. Invalidate();
  536. break;
  537. case SCDR_CANCEL:
  538. break;
  539. case SCDR_NOFREE:
  540. MessageBox(m_view.m_hWnd, _T("All device controls have been assigned for this view."),
  541. _T("Can't reselect control."), MB_OK);
  542. break;
  543. case -1:
  544. MessageBox(m_view.m_hWnd, _T("CSelControlDlg.DoModal() failed."), _T("oops"), MB_OK);
  545. break;
  546. default:
  547. assert(0);
  548. break;
  549. }
  550. }
  551. #endif
  552. //@@END_MSINTERNAL
  553. DWORD CDeviceControl::GetOffset()
  554. {
  555. if (m_bOffsetAssigned)
  556. return m_dwDeviceControlOffset;
  557. return (DWORD)-1;
  558. }
  559. BOOL CDeviceControl::IsOffsetAssigned()
  560. {
  561. return m_bOffsetAssigned;
  562. }
  563. void CDeviceControl::FillImageInfo(DIDEVICEIMAGEINFOW *pImgInfo)
  564. {
  565. if (!pImgInfo) return;
  566. if (m_ptszOverlayPath != NULL)
  567. CopyStr(pImgInfo->tszImagePath, m_ptszOverlayPath, MAX_PATH);
  568. else
  569. wcscpy(pImgInfo->tszImagePath, L""); // Overlay Image not yet supported
  570. SIZE size = {0, 0};
  571. if (m_pbmOverlay != NULL)
  572. m_pbmOverlay->GetSize(&size);
  573. RECT rect = {m_ptOverlay.x, m_ptOverlay.y,
  574. m_ptOverlay.x + size.cx, m_ptOverlay.y + size.cy};
  575. pImgInfo->dwFlags = DIDIFT_OVERLAY; // This is an overlay
  576. pImgInfo->rcOverlay = rect;
  577. pImgInfo->dwObjID = GetOffset();
  578. pImgInfo->dwcValidPts = m_nLinePoints;
  579. DWORD dwPtsToCopy = m_nLinePoints > 5 ? 5 : m_nLinePoints;
  580. for (DWORD i = 0; i < dwPtsToCopy; ++i)
  581. pImgInfo->rgptCalloutLine[i] = m_rgptLinePoint[i];
  582. pImgInfo->rcCalloutRect = m_rectCalloutMax;
  583. pImgInfo->dwTextAlign = m_dwCalloutAlign;
  584. }
  585. //@@BEGIN_MSINTERNAL
  586. #ifdef DDKBUILD
  587. void CDeviceControl::SelectOverlay()
  588. {
  589. LPCTSTR file = GetOpenFileName(
  590. g_hModule,
  591. m_view.m_hWnd,
  592. _T("Select An Overlay Image for This Control"),
  593. _T("PNG Files (*.png)\0*.png\0All Files (*.*)\0*.*\0"),
  594. _T("png"));
  595. if (file == NULL)
  596. return;
  597. ManualLoadImage(file);
  598. }
  599. void CDeviceControl::ManualLoadImage(LPCTSTR tszPath)
  600. {
  601. if (!tszPath)
  602. FormattedErrorBox(g_hModule, m_view.m_hWnd, IDS_TITLE_NOLOADVIEWIMAGE, IDS_NULLPATH);
  603. LPDIRECT3DSURFACE8 pSurf = m_ui.m_uig.GetSurface3D(); // GetSurface3D() calls AddRef() on the surface.
  604. CBitmap *pbmNewImage = CBitmap::CreateViaD3DX(tszPath, pSurf);
  605. if (pSurf)
  606. {
  607. // Release surface instance after we are done with it so we don't leak memory.
  608. pSurf->Release();
  609. pSurf = NULL;
  610. }
  611. if (pbmNewImage == NULL)
  612. {
  613. FormattedErrorBox(g_hModule, m_view.m_hWnd, IDS_TITLE_NOLOADVIEWIMAGE, IDS_COULDNOTCREATEIMAGEFROMFILE, tszPath);
  614. return;
  615. }
  616. // replace
  617. delete m_pbmOverlay;
  618. m_pbmOverlay = pbmNewImage;
  619. pbmNewImage = NULL;
  620. if (m_ptszOverlayPath != NULL)
  621. free(m_ptszOverlayPath);
  622. m_ptszOverlayPath = _tcsdup(tszPath);
  623. // redraw
  624. Invalidate();
  625. }
  626. void CDeviceControl::PositionOverlay(POINT point)
  627. {
  628. SIZE size = {1, 1};
  629. RECT rect = {0, 0, size.cx, size.cy};
  630. PlaceRectCenter(rect, point);
  631. RECT client;
  632. m_view.GetClientRect(&client);
  633. OffsetRectToWithin(rect, client);
  634. SRECT sr = rect;
  635. m_ptOverlay = sr.ul;
  636. Invalidate();
  637. }
  638. #endif
  639. //@@END_MSINTERNAL
  640. BOOL CDeviceControl::IsMapped()
  641. {
  642. return m_ui.IsControlMapped(this);
  643. }
  644. int CDeviceControl::GetControlIndex()
  645. {
  646. for (int i = 0; i < m_view.GetNumControls(); i++)
  647. if (m_view.GetControl(i) == this)
  648. return i;
  649. return -1;
  650. }
  651. void CDeviceControl::SetLinePoints(int n, POINT *rgpt)
  652. {
  653. assert(n >= 0 && n <= MAX_DEVICECONTROL_LINEPOINTS && rgpt);
  654. if (n < 0)
  655. n = 0;
  656. if (n > MAX_DEVICECONTROL_LINEPOINTS)
  657. n = MAX_DEVICECONTROL_LINEPOINTS;
  658. if (!rgpt)
  659. n = 0;
  660. m_nLinePoints = n;
  661. for (int i = 0; i < n; i++)
  662. m_rgptLinePoint[i] = rgpt[i];
  663. }
  664. void CDeviceControl::SetOverlayPath(LPCTSTR tszPath)
  665. {
  666. if (m_ptszOverlayPath)
  667. free(m_ptszOverlayPath);
  668. m_ptszOverlayPath = NULL;
  669. if (tszPath)
  670. m_ptszOverlayPath = _tcsdup(tszPath);
  671. delete m_pbmOverlay;
  672. m_pbmOverlay = NULL;
  673. if (m_ptszOverlayPath)
  674. {
  675. LPDIRECT3DSURFACE8 pSurf = m_ui.m_uig.GetSurface3D(); // GetSurface3D() calls AddRef() on the surface.
  676. m_pbmOverlay = CBitmap::CreateViaD3DX(m_ptszOverlayPath, pSurf);
  677. if (pSurf)
  678. {
  679. // Release surface instance after we are done with it so we don't leak memory.
  680. pSurf->Release();
  681. pSurf = NULL;
  682. }
  683. }
  684. }
  685. void CDeviceControl::SetOverlayRect(const RECT &r)
  686. {
  687. m_ptOverlay.x = r.left;
  688. m_ptOverlay.y = r.top;
  689. }