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.

984 lines
31 KiB

  1. //------------------------------------------------------------------------------
  2. // idroptgt.cpp
  3. // Copyright (c)1997-1999 Microsoft Corporation, All Rights Reserved
  4. //
  5. // Author
  6. // bash
  7. //
  8. // History
  9. // 7-15-97 created (bash)
  10. //
  11. // Implementation of IDropTarget
  12. //
  13. //------------------------------------------------------------------------------
  14. #include "stdafx.h"
  15. #include <ocidl.h>
  16. #include <string.h>
  17. #include "triedit.h"
  18. #include "document.h"
  19. #include "privcid.h"
  20. #include "dispatch.h"
  21. #include "trace.h"
  22. #include "undo.h"
  23. ///////////////////////////////////////////////////////////////////////////////
  24. //
  25. // CTriEditDocument::DragEnter (IDropTarget method)
  26. //
  27. // In design mode, accept drags that originate within Trident. Allow unlocked
  28. // 2D positioned elements to be dragged using a dashed outline as a drag
  29. // rectangle. If TriEdit's constrained dragging mode has been enabled using
  30. // the Constrain method then the drag will be constrained to points which are
  31. // even multiples of the values in m_ptConstrain.
  32. //
  33. STDMETHODIMP CTriEditDocument::DragEnter(IDataObject *pDataObject,
  34. DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  35. {
  36. HRESULT hr = GetElement(TRUE /* fInDragDrop */);
  37. m_fLocked = FALSE;
  38. m_eDirection = CONSTRAIN_NONE;
  39. if (SUCCEEDED(hr) &&
  40. m_pihtmlElement &&
  41. SUCCEEDED(hr=GetTridentWindow()))
  42. {
  43. BOOL f2D = FALSE;
  44. LONG lWidth;
  45. LONG lHeight;
  46. IHTMLElement* pihtmlElementParent=NULL;
  47. HBITMAP hbmp;
  48. _ASSERTE(m_pihtmlStyle);
  49. if (IsDesignMode() && //Are we in design mode?
  50. m_pihtmlStyle && //abort if don't have style
  51. IsDragSource() && //abort if Trident isn't source of drag
  52. SUCCEEDED(Is2DElement(m_pihtmlElement, &f2D)) && f2D &&
  53. SUCCEEDED(IsLocked(m_pihtmlElement, &m_fLocked)) && !m_fLocked &&
  54. SUCCEEDED(GetScrollPosition()) &&
  55. SUCCEEDED(GetElementPosition(m_pihtmlElement, &m_rcElement)))
  56. {
  57. //first, let's get a pattern brush to use for the move rectangle
  58. hbmp = LoadBitmap(_Module.GetModuleInstance(), (LPCWSTR)IDR_FEEDBACKRECTBMP);
  59. _ASSERTE(hbmp);
  60. m_hbrDragRect = CreatePatternBrush(hbmp);
  61. _ASSERTE(m_hbrDragRect);
  62. DeleteObject(hbmp);
  63. ::SetRect(&m_rcElementParent, 0, 0, 0, 0);
  64. hr = m_pihtmlElement->get_offsetParent(&pihtmlElementParent);
  65. if (SUCCEEDED(hr) && pihtmlElementParent)
  66. {
  67. GetElementPosition(pihtmlElementParent, &m_rcElementParent);
  68. }
  69. SAFERELEASE(pihtmlElementParent);
  70. lWidth = m_rcElement.right - m_rcElement.left;
  71. lHeight = m_rcElement.bottom - m_rcElement.top;
  72. //this is where we'll initially draw the drag rectangle
  73. m_rcDragRect = m_rcElementOrig = m_rcElement;
  74. //convert clicked point to client coordinates
  75. m_ptClickLast.x = pt.x;
  76. m_ptClickLast.y = pt.y;
  77. ScreenToClient(m_hwndTrident, &m_ptClickLast);
  78. //save point in doc coordinates where clicked.
  79. m_ptClickOrig = m_ptClickLast;
  80. m_ptClickOrig.x += m_ptScroll.x;
  81. m_ptClickOrig.y += m_ptScroll.y;
  82. if (m_fConstrain)
  83. {
  84. m_ptConstrain.x = m_rcElement.left;
  85. m_ptConstrain.y = m_rcElement.top;
  86. }
  87. #define BORDER_WIDTH 7
  88. if (m_ptClickOrig.x < (m_rcDragRect.left - BORDER_WIDTH))
  89. {
  90. m_rcDragRect.left = m_ptClickOrig.x;
  91. m_rcDragRect.right = m_rcDragRect.left + lWidth;
  92. }
  93. else if (m_ptClickOrig.x > (m_rcDragRect.right + BORDER_WIDTH))
  94. {
  95. m_rcDragRect.right = m_ptClickOrig.x;
  96. m_rcDragRect.left = m_rcDragRect.right - lWidth;
  97. }
  98. if (m_ptClickOrig.y < (m_rcDragRect.top - BORDER_WIDTH))
  99. {
  100. m_rcDragRect.top = m_ptClickOrig.y;
  101. m_rcDragRect.bottom = m_rcDragRect.top + lHeight;
  102. }
  103. else if (m_ptClickOrig.y > (m_rcDragRect.bottom + BORDER_WIDTH))
  104. {
  105. m_rcDragRect.bottom = m_ptClickOrig.y;
  106. m_rcDragRect.top = m_rcDragRect.bottom - lHeight;
  107. }
  108. m_rcElement = m_rcDragRect;
  109. //Trace("DragEnter: m_rcElement(%d,%d,%d,%d)", m_rcElement.left, m_rcElement.top, m_rcElement.right, m_rcElement.bottom);
  110. //Trace("DragEnter: m_rcDragRect(%d,%d,%d,%d)", m_rcDragRect.left, m_rcDragRect.top, m_rcDragRect.right, m_rcDragRect.bottom);
  111. //Trace("DragEnter: m_ptClickLast(%d,%d)", m_ptClickLast.x, m_ptClickLast.y);
  112. //Trace("DragEnter: m_ptClickOrig(%d,%d)", m_ptClickOrig.x, m_ptClickOrig.y);
  113. //now draw the selection rect
  114. Draw2DDragRect(TRUE);
  115. *pdwEffect = DROPEFFECT_MOVE;
  116. hr = S_OK;
  117. }
  118. else
  119. if (!m_fLocked)
  120. {
  121. //something is hosed. just bail
  122. ReleaseElement();
  123. }
  124. }
  125. if (!m_pihtmlElement && NULL != m_pDropTgtTrident)
  126. {
  127. hr = m_pDropTgtTrident->DragEnter(pDataObject, grfKeyState, pt, pdwEffect);
  128. }
  129. return hr;
  130. }
  131. ///////////////////////////////////////////////////////////////////////////////
  132. //
  133. // CTriEditDocument::DragOver (IDropTarget method)
  134. //
  135. // Provide feedback during a drag, updating the drag rectangle, and scrolling
  136. // the document as needed.
  137. STDMETHODIMP CTriEditDocument::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  138. {
  139. HRESULT hr = E_UNEXPECTED;
  140. POINT ptClient;
  141. if (m_pihtmlElement &&
  142. !m_fLocked &&
  143. SUCCEEDED(GetScrollPosition())) //we are handling the drag-drop
  144. {
  145. ptClient.x = pt.x;
  146. ptClient.y = pt.y;
  147. ScreenToClient(m_hwndTrident, &ptClient);
  148. // scroll if required
  149. if (S_OK == DragScroll(ptClient))
  150. {
  151. *pdwEffect = DROPEFFECT_MOVE | DROPEFFECT_SCROLL;
  152. }
  153. else
  154. {
  155. if (ptClient.x != m_ptClickLast.x || ptClient.y != m_ptClickLast.y)
  156. {
  157. //update the last click position
  158. m_ptClickLast.x = ptClient.x;
  159. m_ptClickLast.y = ptClient.y;
  160. //Trace("DragOver: m_ptClickLast(%d,%d)", m_ptClickLast.x, m_ptClickLast.y);
  161. //erase the move rectangle
  162. Draw2DDragRect(FALSE);
  163. ConstrainXY(&ptClient);
  164. SnapToGrid(&ptClient);
  165. //redraw the move rectangle
  166. Draw2DDragRect(TRUE);
  167. }
  168. *pdwEffect = DROPEFFECT_MOVE;
  169. }
  170. hr = S_OK;
  171. }
  172. if (!m_pihtmlElement && NULL != m_pDropTgtTrident)
  173. {
  174. hr = m_pDropTgtTrident->DragOver(grfKeyState, pt, pdwEffect);
  175. }
  176. return hr;
  177. }
  178. ///////////////////////////////////////////////////////////////////////////////
  179. //
  180. // CTriEditDocument::DragLeave (IDropTarget method)
  181. //
  182. // If currently dragging, erase the drag rectangle.
  183. //
  184. STDMETHODIMP CTriEditDocument::DragLeave()
  185. {
  186. HRESULT hr = E_UNEXPECTED;
  187. if (m_pihtmlElement && !m_fLocked)
  188. {
  189. //erase the move rectangle
  190. Draw2DDragRect(FALSE);
  191. if (m_hbrDragRect)
  192. {
  193. DeleteObject(m_hbrDragRect);
  194. m_hbrDragRect = NULL;
  195. }
  196. hr = S_OK;
  197. }
  198. else if (!m_pihtmlElement && NULL != m_pDropTgtTrident)
  199. {
  200. hr = m_pDropTgtTrident->DragLeave();
  201. }
  202. ReleaseElement();
  203. return hr;
  204. }
  205. ///////////////////////////////////////////////////////////////////////////////
  206. //
  207. // CTriEditDocument::Drop (IDropTarget method)
  208. //
  209. // After a successful drag of an unlocked element, erase the drag rectangle
  210. // and then handle the actual drop by moving or creating an item. Newly
  211. // created items will be 2D positionable.
  212. //
  213. STDMETHODIMP CTriEditDocument::Drop(IDataObject *pDataObject,
  214. DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  215. {
  216. HRESULT hr = E_UNEXPECTED;
  217. if (m_pihtmlElement && !m_fLocked)
  218. {
  219. _ASSERTE(m_pihtmlElement);
  220. _ASSERTE(m_pihtmlStyle);
  221. //erase the move rectangle
  222. Draw2DDragRect(FALSE);
  223. if (m_hbrDragRect)
  224. {
  225. DeleteObject(m_hbrDragRect);
  226. m_hbrDragRect = NULL;
  227. }
  228. if (m_pihtmlStyle)
  229. {
  230. POINT ptOrig, ptMove;
  231. m_rcDragRect.left = m_rcDragRect.left - m_rcElementParent.left;
  232. m_rcDragRect.top = m_rcDragRect.top - m_rcElementParent.top;
  233. m_rcDragRect.right = m_rcDragRect.right - m_rcElementParent.right;
  234. m_rcDragRect.bottom = m_rcDragRect.bottom - m_rcElementParent.bottom;
  235. ptOrig.x = m_rcElementOrig.left;
  236. ptOrig.y = m_rcElementOrig.top;
  237. ptMove.x = m_rcDragRect.left;
  238. ptMove.y = m_rcDragRect.top;
  239. CUndoDrag* pUndoDrag = new CUndoDrag(m_pihtmlStyle, ptOrig, ptMove);
  240. if (pUndoDrag) //constructor sets m_cRef=1
  241. {
  242. hr = AddUndoUnit(m_pUnkTrident, pUndoDrag);
  243. _ASSERTE(SUCCEEDED(hr));
  244. pUndoDrag->Release();
  245. }
  246. m_pihtmlStyle->put_pixelLeft(m_rcDragRect.left);
  247. m_pihtmlStyle->put_pixelTop(m_rcDragRect.top);
  248. }
  249. //cleanup
  250. hr = S_OK;
  251. }
  252. if (!m_pihtmlElement && NULL != m_pDropTgtTrident)
  253. {
  254. hr = m_pDropTgtTrident->Drop(pDataObject, grfKeyState, pt, pdwEffect);
  255. // The following is to workaround a Trident bug where they don't
  256. // set the focus to their window upon the drop
  257. if (S_OK == hr)
  258. {
  259. CComPtr<IOleInPlaceSite> pInPlaceSite;
  260. CComPtr<IOleInPlaceFrame> pInPlaceFrame;
  261. CComPtr<IOleInPlaceUIWindow> pInPlaceWindow;
  262. RECT posRect, clipRect;
  263. OLEINPLACEFRAMEINFO frameInfo;
  264. HWND hwnd, hwndFrame;
  265. if (S_OK == m_pClientSiteHost->QueryInterface(IID_IOleInPlaceSite, (void **)&pInPlaceSite))
  266. {
  267. _ASSERTE(NULL != pInPlaceSite.p);
  268. if (S_OK == pInPlaceSite->GetWindowContext(&pInPlaceFrame, &pInPlaceWindow, &posRect, &clipRect, &frameInfo))
  269. {
  270. if (NULL != pInPlaceWindow.p)
  271. pInPlaceWindow->GetWindow(&hwnd);
  272. else
  273. {
  274. _ASSERTE(NULL != pInPlaceFrame.p);
  275. pInPlaceFrame->GetWindow(&hwnd);
  276. }
  277. // We need to walk up the parent chain till we find a frame window to work around a Vegas bug
  278. // Note that this is generic enough to do the right thing for all of our clients
  279. hwndFrame = hwnd;
  280. do
  281. {
  282. if (GetWindowLong(hwndFrame, GWL_STYLE) & WS_THICKFRAME)
  283. break;
  284. hwndFrame = GetParent(hwndFrame);
  285. }
  286. while (hwndFrame);
  287. SetFocus(hwndFrame && IsWindow(hwndFrame) ? hwndFrame : hwnd);
  288. }
  289. }
  290. }
  291. // Handle 2d drop mode here
  292. if (S_OK == hr && !IsDragSource())
  293. {
  294. BOOL f2DCapable = FALSE;
  295. BOOL f2D = FALSE;
  296. GetElement();
  297. // we do the following if we are in 2DDropMode and the element is 2DCapable
  298. // and the element is not already 2D or a DTC
  299. if (m_f2dDropMode && m_pihtmlElement &&
  300. SUCCEEDED(Is2DCapable(m_pihtmlElement, &f2DCapable)) && f2DCapable &&
  301. SUCCEEDED(Is2DElement(m_pihtmlElement, &f2D)) && !f2D &&
  302. FAILED(IsElementDTC(m_pihtmlElement)))
  303. {
  304. HRESULT hr;
  305. POINT ptClient;
  306. ptClient.x = pt.x;
  307. ptClient.y = pt.y;
  308. if (SUCCEEDED(hr = CalculateNewDropPosition(&ptClient)))
  309. hr = Make2DElement(m_pihtmlElement, &ptClient);
  310. else
  311. hr = Make2DElement(m_pihtmlElement);
  312. _ASSERTE(SUCCEEDED(hr));
  313. }
  314. if (m_pihtmlElement)
  315. {
  316. BOOL f2D = FALSE;
  317. VARIANT var;
  318. POINT ptClient;
  319. ptClient.x = pt.x;
  320. ptClient.y = pt.y;
  321. if (SUCCEEDED(Is2DElement(m_pihtmlElement, &f2D)) && f2D)
  322. {
  323. if (SUCCEEDED(CalculateNewDropPosition(&ptClient)))
  324. {
  325. IHTMLElement *pihtmlElementParent = NULL;
  326. m_pihtmlElement->get_offsetParent(&pihtmlElementParent);
  327. if(pihtmlElementParent)
  328. {
  329. RECT rcParent;
  330. if (SUCCEEDED(GetElementPosition(pihtmlElementParent, &rcParent)))
  331. {
  332. m_pihtmlStyle->put_pixelLeft(ptClient.x - rcParent.left);
  333. m_pihtmlStyle->put_pixelTop(ptClient.y - rcParent.top);
  334. }
  335. SAFERELEASE(pihtmlElementParent);
  336. }
  337. }
  338. VariantInit(&var);
  339. var.vt = VT_I4;
  340. var.lVal = 0;
  341. m_pihtmlStyle->put_zIndex(var);
  342. AssignZIndex(m_pihtmlElement, MADE_ABSOLUTE);
  343. }
  344. }
  345. }
  346. }
  347. ReleaseElement();
  348. return hr;
  349. }
  350. ///////////////////////////////////////////////////////////////////////////////
  351. //
  352. // CTriEditDocument::GetElement
  353. //
  354. // Fetch the current Trident element and its style into m_pihtmlElement and
  355. // m_pihtmlStyle, respectively. If currently in mid-drag-drop (as indicated
  356. // by fInDragDrop) then do not accept an HTML element of type "Text" as
  357. // the currrent element. Returns S_OK or a Trident error.
  358. //
  359. HRESULT CTriEditDocument::GetElement(BOOL fInDragDrop)
  360. {
  361. IHTMLDocument2* pihtmlDoc2=NULL;
  362. IHTMLSelectionObject* pihtmlSelObj=NULL;
  363. IHTMLTxtRange* pihtmlTxtRange=NULL;
  364. IHTMLControlRange* pihtmlControlRange=NULL;
  365. IHTMLElement* pihtmlBodyElement=NULL;
  366. IUnknown* punkBody=NULL;
  367. IUnknown* punkElement=NULL;
  368. IDispatch* pidisp=NULL;
  369. BSTR bstrType=NULL;
  370. ReleaseElement(); //cleanup just in case...
  371. _ASSERTE(m_pUnkTrident);
  372. HRESULT hr = GetDocument(&pihtmlDoc2);
  373. if (FAILED(hr))
  374. goto CleanUp;
  375. hr = pihtmlDoc2->get_selection(&pihtmlSelObj);
  376. if (FAILED(hr))
  377. goto CleanUp;
  378. _ASSERTE(pihtmlSelObj);
  379. hr = pihtmlSelObj->get_type(&bstrType);
  380. _ASSERTE(SUCCEEDED(hr));
  381. if (FAILED(hr) || !bstrType || (fInDragDrop && _wcsicmp(bstrType, L"Text")==0))
  382. goto CleanUp;
  383. hr = pihtmlSelObj->createRange(&pidisp);
  384. if (FAILED(hr) || !pidisp)
  385. goto CleanUp;
  386. hr = pidisp->QueryInterface(IID_IHTMLTxtRange, (LPVOID*)&pihtmlTxtRange);
  387. if (SUCCEEDED(hr))
  388. {
  389. _ASSERTE(pihtmlTxtRange);
  390. hr = pihtmlTxtRange->parentElement(&m_pihtmlElement);
  391. goto CleanUp;
  392. }
  393. hr = pidisp->QueryInterface(IID_IHTMLControlRange, (LPVOID*)&pihtmlControlRange);
  394. if (SUCCEEDED(hr))
  395. {
  396. _ASSERTE(pihtmlControlRange);
  397. hr = pihtmlControlRange->commonParentElement(&m_pihtmlElement);
  398. }
  399. CleanUp:
  400. hr = E_FAIL;
  401. if (m_pihtmlElement)
  402. {
  403. //get the body element
  404. hr = pihtmlDoc2->get_body(&pihtmlBodyElement);
  405. _ASSERTE(SUCCEEDED(hr));
  406. if (SUCCEEDED(hr))
  407. {
  408. //get their IUnknowns
  409. hr = pihtmlBodyElement->QueryInterface(IID_IUnknown, (LPVOID*)&punkBody);
  410. _ASSERTE(SUCCEEDED(hr));
  411. hr = m_pihtmlElement->QueryInterface(IID_IUnknown, (LPVOID*)&punkElement);
  412. _ASSERTE(SUCCEEDED(hr));
  413. //If they're equivalent, the body element is the current element
  414. //and we don't want it.
  415. if (punkBody == punkElement)
  416. {
  417. hr = E_FAIL;
  418. }
  419. }
  420. // VID98 bug 2647: if type is none, don't bother to cache style.
  421. // This is to workaround trident crash bug
  422. if (SUCCEEDED(hr) && bstrType && _wcsicmp(bstrType, L"None")!=0)
  423. {
  424. hr = m_pihtmlElement->get_style(&m_pihtmlStyle);
  425. _ASSERTE(SUCCEEDED(hr));
  426. _ASSERTE(m_pihtmlStyle);
  427. }
  428. if (FAILED(hr) || !m_pihtmlStyle)
  429. {
  430. ReleaseElement();
  431. }
  432. hr = S_OK;
  433. }
  434. SAFERELEASE(pihtmlDoc2);
  435. SAFERELEASE(pihtmlSelObj);
  436. SAFERELEASE(pidisp);
  437. SAFERELEASE(pihtmlTxtRange);
  438. SAFERELEASE(pihtmlControlRange);
  439. SAFERELEASE(pihtmlBodyElement);
  440. SAFERELEASE(punkBody);
  441. SAFERELEASE(punkElement);
  442. SysFreeString(bstrType);
  443. return hr;
  444. }
  445. ///////////////////////////////////////////////////////////////////////////////
  446. //
  447. // CTriEditDocument::ReleaseElement
  448. //
  449. // Release any cached reference to the current Trident element and its
  450. // associated style. No return value.
  451. //
  452. void CTriEditDocument::ReleaseElement(void)
  453. {
  454. SAFERELEASE(m_pihtmlElement);
  455. SAFERELEASE(m_pihtmlStyle);
  456. }
  457. ///////////////////////////////////////////////////////////////////////////////
  458. //
  459. // CTriEditDocument::Draw2DDragRect
  460. //
  461. // After giving the drag-drop handler host a chance to draw the drag rectangle,
  462. // draw the rectangle if the handler choose not to do so. No return value.
  463. //
  464. void CTriEditDocument::Draw2DDragRect(BOOL fDraw)
  465. {
  466. RECT rect = m_rcDragRect;
  467. // S_FALSE means that the host has already drawn its own feedback
  468. if (m_pDragDropHandlerHost && m_pDragDropHandlerHost->DrawDragFeedback(&rect) == S_FALSE)
  469. return;
  470. if ((fDraw == m_fDragRectVisible) || (NULL == m_hwndTrident) || (NULL == m_hbrDragRect))
  471. return;
  472. HDC hdc = GetDC(m_hwndTrident);
  473. _ASSERTE(hdc);
  474. HBRUSH hbrOld = (HBRUSH)SelectObject(hdc, m_hbrDragRect);
  475. _ASSERTE(hbrOld);
  476. //BUGS:M3-2723\The Drag Rectangle Must be at Least 8x8 pixels
  477. LONG lWidth = max((rect.right - rect.left), 16);
  478. LONG lHeight = max((rect.bottom - rect.top), 16);
  479. SetWindowOrgEx(hdc, m_ptScroll.x, m_ptScroll.y, NULL);
  480. //A Value of 2 is added to the rect's left and top in all the following PatBlt function
  481. //to work around a rounding off bug caused by trident.
  482. PatBlt( hdc, rect.left + 2, rect.top + 2,
  483. lWidth, 1, PATINVERT);
  484. PatBlt( hdc, rect.left + 2, rect.top + lHeight + 1, //(2 - 1)
  485. lWidth, 1, PATINVERT);
  486. PatBlt( hdc, rect.left + 2, rect.top + 3,//(2 + 1)
  487. 1, lHeight - (2 * 1), PATINVERT);
  488. PatBlt( hdc, rect.left + lWidth + 1 /*(2 - 1)*/, rect.top + 3, //(2 + 1)
  489. 1, lHeight - (2 * 1), PATINVERT);
  490. m_fDragRectVisible = !m_fDragRectVisible;
  491. SelectObject(hdc, hbrOld);
  492. ReleaseDC(m_hwndTrident, hdc);
  493. }
  494. ///////////////////////////////////////////////////////////////////////////////
  495. //
  496. // CTriEditDocument::GetScrollPosition
  497. //
  498. // Get the Trident document's scroll position and store it in m_ptScroll.
  499. // Return S_OK or a Trident error code.
  500. //
  501. HRESULT CTriEditDocument::GetScrollPosition(void)
  502. {
  503. IHTMLDocument2* pihtmlDoc2=NULL;
  504. IHTMLTextContainer* pihtmlTextContainer=NULL;
  505. IHTMLElement* pihtmlElement=NULL;
  506. HRESULT hr = E_FAIL;
  507. _ASSERTE(m_pUnkTrident);
  508. if (SUCCEEDED(GetDocument(&pihtmlDoc2)))
  509. {
  510. if (SUCCEEDED(pihtmlDoc2->get_body(&pihtmlElement)))
  511. {
  512. _ASSERTE(pihtmlElement);
  513. if (pihtmlElement)
  514. {
  515. if (SUCCEEDED(pihtmlElement->QueryInterface(IID_IHTMLTextContainer,
  516. (LPVOID*)&pihtmlTextContainer)))
  517. {
  518. _ASSERTE(pihtmlTextContainer);
  519. if (pihtmlTextContainer)
  520. {
  521. hr = pihtmlTextContainer->get_scrollLeft(&m_ptScroll.x);
  522. _ASSERTE(SUCCEEDED(hr));
  523. hr = pihtmlTextContainer->get_scrollTop(&m_ptScroll.y);
  524. _ASSERTE(SUCCEEDED(hr));
  525. hr = S_OK;
  526. }
  527. }
  528. }
  529. }
  530. }
  531. SAFERELEASE(pihtmlDoc2);
  532. SAFERELEASE(pihtmlTextContainer);
  533. SAFERELEASE(pihtmlElement);
  534. return hr;
  535. }
  536. ///////////////////////////////////////////////////////////////////////////////
  537. //
  538. // CTriEditDocument::DragScroll
  539. //
  540. // Scroll the Trident document so as to make the given point visible. If a
  541. // drag rectangle is visible it will be erased before any scrolling occurs;
  542. // the caller is responsible for redrawing the rectangle. Returns S_OK if the
  543. // document was scrolled, S_FALSE if not scrolling was required, or a
  544. // Trident error.
  545. //
  546. #define nScrollInset 5
  547. HRESULT CTriEditDocument::DragScroll(POINT pt)
  548. {
  549. RECT rectClient, rect;
  550. long x = 0, y = 0;
  551. IHTMLDocument2* pihtmlDoc2=NULL;
  552. IHTMLWindow2* pihtmlWindow2=NULL;
  553. GetClientRect(m_hwndTrident, &rectClient);
  554. rect = rectClient;
  555. InflateRect(&rect, -nScrollInset, -nScrollInset);
  556. if (PtInRect(&rectClient, pt) && !PtInRect(&rect, pt))
  557. {
  558. // determine direction of scroll along both X & Y axis
  559. if (pt.x < rect.left)
  560. x = -nScrollInset;
  561. else if (pt.x >= rect.right)
  562. x = nScrollInset;
  563. if (pt.y < rect.top)
  564. y = -nScrollInset;
  565. else if (pt.y >= rect.bottom)
  566. y = nScrollInset;
  567. }
  568. if (x == 0 && y == 0) // no scrolling required
  569. return S_FALSE;
  570. _ASSERTE(m_pUnkTrident);
  571. if (SUCCEEDED(GetDocument(&pihtmlDoc2)))
  572. {
  573. _ASSERTE(pihtmlDoc2);
  574. if (SUCCEEDED(pihtmlDoc2->get_parentWindow(&pihtmlWindow2)))
  575. {
  576. _ASSERTE(pihtmlWindow2);
  577. // erase move rectangle before scrolling
  578. Draw2DDragRect(FALSE);
  579. pihtmlWindow2->scrollBy(x,y);
  580. }
  581. }
  582. SAFERELEASE(pihtmlDoc2);
  583. SAFERELEASE(pihtmlWindow2);
  584. return S_OK;
  585. }
  586. ///////////////////////////////////////////////////////////////////////////////
  587. //
  588. // CTriEditDocument::IsDragSource
  589. //
  590. // Return TRUE if the current OLE drag-drop was originated by Trident, or
  591. // FALSE otherwise.
  592. //
  593. BOOL CTriEditDocument::IsDragSource(void)
  594. {
  595. BOOL fDragSource = FALSE;
  596. HRESULT hr;
  597. VARIANT var;
  598. if (m_pUnkTrident)
  599. {
  600. IOleCommandTarget* pioleCmdTarget;
  601. if (SUCCEEDED(m_pUnkTrident->QueryInterface(IID_IOleCommandTarget,
  602. (LPVOID*)&pioleCmdTarget)))
  603. {
  604. _ASSERTE(pioleCmdTarget);
  605. if (pioleCmdTarget)
  606. {
  607. VariantInit(&var);
  608. var.vt = VT_BOOL;
  609. var.boolVal = FALSE;
  610. hr = pioleCmdTarget->Exec( &CMDSETID_Forms3,
  611. IDM_SHDV_ISDRAGSOURCE,
  612. MSOCMDEXECOPT_DONTPROMPTUSER,
  613. NULL,
  614. &var );
  615. _ASSERTE(SUCCEEDED(hr));
  616. fDragSource = (var.boolVal) ? TRUE:FALSE;
  617. pioleCmdTarget->Release();
  618. }
  619. }
  620. }
  621. return fDragSource;
  622. }
  623. ///////////////////////////////////////////////////////////////////////////////
  624. //
  625. // CTriEditDocument::ConstrainXY
  626. //
  627. // If TriEdit's constrained dragging mode is enabled, constrain the
  628. // rectangle of the current element (m_rcElement) vis-a-vis the given
  629. // point according to the current constraint direction, first computing
  630. // the constraint direction if necessary. Return S_OK.
  631. //
  632. HRESULT CTriEditDocument::ConstrainXY(LPPOINT lppt) //pt is in client coordinates
  633. {
  634. POINT ptRel;
  635. if (m_fConstrain)
  636. {
  637. if (CONSTRAIN_NONE == m_eDirection)
  638. {
  639. ptRel.x = (lppt->x + m_ptScroll.x) - m_ptClickOrig.x;
  640. ptRel.y = (lppt->y + m_ptScroll.y) - m_ptClickOrig.y;
  641. if ((ptRel.x && !ptRel.y) || (abs(ptRel.x) > abs(ptRel.y)))
  642. m_eDirection = CONSTRAIN_HORIZONTAL;
  643. else
  644. if ((!ptRel.y && ptRel.y) || (abs(ptRel.y) > abs(ptRel.x)))
  645. m_eDirection = CONSTRAIN_VERTICAL;
  646. else
  647. m_eDirection = CONSTRAIN_HORIZONTAL;
  648. if (m_eDirection == CONSTRAIN_VERTICAL)
  649. {
  650. LONG lWidth = m_rcElement.right - m_rcElement.left;
  651. m_ptClickOrig.x = m_rcElement.left = m_ptConstrain.x;
  652. m_rcElement.right = m_rcElement.left + lWidth;
  653. }
  654. else
  655. {
  656. LONG lHeight = m_rcElement.bottom - m_rcElement.top;
  657. m_ptClickOrig.y = m_rcElement.top = m_ptConstrain.y;
  658. m_rcElement.bottom = m_rcElement.top + lHeight;
  659. }
  660. }
  661. switch(m_eDirection)
  662. {
  663. case CONSTRAIN_HORIZONTAL:
  664. lppt->y = (m_ptClickOrig.y - m_ptScroll.y);
  665. break;
  666. case CONSTRAIN_VERTICAL:
  667. lppt->x = (m_ptClickOrig.x - m_ptScroll.x);
  668. break;
  669. }
  670. }
  671. return S_OK;
  672. }
  673. ///////////////////////////////////////////////////////////////////////////////
  674. //
  675. // CTriEditDocument::SnapToGrid
  676. //
  677. // Snap the appropriate edge of the current HTML element (m_rcElement) to the
  678. // given point, modulo the current TriEdit grid setting. Return S_OK.
  679. //
  680. HRESULT CTriEditDocument::SnapToGrid(LPPOINT lppt) //pt is in client coordinates
  681. {
  682. POINT ptRel;
  683. POINT ptDoc;
  684. _ASSERTE(lppt);
  685. //determine relative movement
  686. ptRel.x = (lppt->x + m_ptScroll.x) - m_ptClickOrig.x;
  687. ptRel.y = (lppt->y + m_ptScroll.y) - m_ptClickOrig.y;
  688. ptDoc.x = m_rcElement.left - m_rcElementParent.left + ptRel.x;
  689. ptDoc.y = m_rcElement.top - m_rcElementParent.top + ptRel.y;
  690. if (ptRel.x < 0) //LEFT
  691. {
  692. if (ptDoc.x % m_ptAlign.x)
  693. ptDoc.x -= (ptDoc.x % m_ptAlign.x);
  694. else
  695. ptDoc.x -= m_ptAlign.x;
  696. }
  697. else
  698. if (ptRel.x > 0) //RIGHT
  699. {
  700. if (ptDoc.x % m_ptAlign.x)
  701. ptDoc.x += m_ptAlign.x - (ptDoc.x % m_ptAlign.x);
  702. else
  703. ptDoc.x += m_ptAlign.x;
  704. }
  705. if (ptRel.y < 0) //UP
  706. {
  707. if (ptDoc.y % m_ptAlign.y)
  708. ptDoc.y -= (ptDoc.y % m_ptAlign.y);
  709. else
  710. ptDoc.y -= m_ptAlign.y;
  711. }
  712. else
  713. if (ptRel.y > 0) //DOWN
  714. {
  715. if (ptDoc.y % m_ptAlign.y)
  716. ptDoc.y += m_ptAlign.y - (ptDoc.y % m_ptAlign.y);
  717. else
  718. ptDoc.y += m_ptAlign.y;
  719. }
  720. m_rcDragRect.left = m_rcElementParent.left + ptDoc.x;
  721. m_rcDragRect.top = m_rcElementParent.top + ptDoc.y;
  722. m_rcDragRect.right = m_rcDragRect.left + (m_rcElement.right - m_rcElement.left);
  723. m_rcDragRect.bottom = m_rcDragRect.top + (m_rcElement.bottom - m_rcElement.top);
  724. return S_OK;
  725. }
  726. ///////////////////////////////////////////////////////////////////////////////
  727. //
  728. // CTriEditDocument::IsDesignMode
  729. //
  730. // Return TRUE if Trident is in design (edit) mode, or FALSE if it is in
  731. // browse mode.
  732. //
  733. BOOL CTriEditDocument::IsDesignMode(void)
  734. {
  735. HRESULT hr;
  736. OLECMD olecmd;
  737. olecmd.cmdID = IDM_EDITMODE;
  738. hr = m_pCmdTgtTrident->QueryStatus(&CMDSETID_Forms3, 1, &olecmd, NULL);
  739. return (SUCCEEDED(hr) && (olecmd.cmdf & OLECMDF_LATCHED));
  740. }
  741. ///////////////////////////////////////////////////////////////////////////////
  742. //
  743. // CTriEditDocument::GetElementPosition
  744. //
  745. // Return (under prc) the position of the given HTML element in document
  746. // coordinates. Return S_OK or a Trident error code as the return value.
  747. //
  748. HRESULT CTriEditDocument::GetElementPosition(IHTMLElement* pihtmlElement, LPRECT prc)
  749. {
  750. IHTMLElement* pelem = NULL;
  751. IHTMLElement* pelemNext = NULL;
  752. POINT ptExtent;
  753. HRESULT hr;
  754. _ASSERTE(pihtmlElement && prc);
  755. if(!pihtmlElement || !prc)
  756. return E_POINTER;
  757. if(FAILED(pihtmlElement->get_offsetLeft(&prc->left)))
  758. return(E_FAIL);
  759. if(FAILED(pihtmlElement->get_offsetTop(&prc->top)))
  760. return(E_FAIL);
  761. hr = pihtmlElement->get_offsetParent(&pelemNext);
  762. while (SUCCEEDED(hr) && pelemNext)
  763. {
  764. POINT pt;
  765. if(FAILED(hr = pelemNext->get_offsetLeft(&pt.x)))
  766. goto QuickExit;
  767. if(FAILED(hr = pelemNext->get_offsetTop(&pt.y)))
  768. goto QuickExit;
  769. prc->left += pt.x;
  770. prc->top += pt.y;
  771. pelem = pelemNext;
  772. pelemNext = NULL;
  773. hr = pelem->get_offsetParent(&pelemNext);
  774. SAFERELEASE(pelem);
  775. }
  776. if (FAILED(hr = pihtmlElement->get_offsetWidth(&ptExtent.x)))
  777. goto QuickExit;
  778. if (FAILED(hr = pihtmlElement->get_offsetHeight(&ptExtent.y)))
  779. goto QuickExit;
  780. prc->right = prc->left + ptExtent.x;
  781. prc->bottom = prc->top + ptExtent.y;
  782. QuickExit:
  783. _ASSERTE(SUCCEEDED(hr));
  784. SAFERELEASE(pelem);
  785. SAFERELEASE(pelemNext);
  786. return hr;
  787. }
  788. ///////////////////////////////////////////////////////////////////////////////
  789. //
  790. // CTriEditDocument::GetTridentWindow
  791. //
  792. // Fetch the IOleWindow interface of the Trident instance in to m_hwndTrident.
  793. // Return S_OK or the Trident error code.
  794. //
  795. STDMETHODIMP CTriEditDocument::GetTridentWindow()
  796. {
  797. LPOLEWINDOW piolewinTrident;
  798. HRESULT hr = E_FAIL;
  799. if( m_pOleObjTrident &&
  800. SUCCEEDED(hr = m_pOleObjTrident->QueryInterface(IID_IOleWindow, (LPVOID*)&piolewinTrident)))
  801. {
  802. m_hwndTrident = NULL;
  803. hr = piolewinTrident->GetWindow(&m_hwndTrident);
  804. _ASSERTE(m_hwndTrident != NULL);
  805. piolewinTrident->Release();
  806. }
  807. _ASSERTE(SUCCEEDED(hr));
  808. return hr;
  809. }
  810. ///////////////////////////////////////////////////////////////////////////////
  811. //
  812. // CTriEditDocument::CalculateNewDropPosition
  813. //
  814. // Adjust the given point to adjust for the fact that the Trident document may
  815. // be scrolled. Return S_OK or a Trident error code.
  816. HRESULT CTriEditDocument::CalculateNewDropPosition(POINT *pt)
  817. {
  818. HRESULT hr = E_FAIL;
  819. if (SUCCEEDED(hr = GetTridentWindow()) &&
  820. ScreenToClient(m_hwndTrident, pt) &&
  821. SUCCEEDED(hr = GetScrollPosition()))
  822. {
  823. pt->x += m_ptScroll.x;
  824. pt->y += m_ptScroll.y;
  825. }
  826. return hr;
  827. }