//------------------------------------------------------------------------------ // idroptgt.cpp // Copyright (c)1997-1999 Microsoft Corporation, All Rights Reserved // // Author // bash // // History // 7-15-97 created (bash) // // Implementation of IDropTarget // //------------------------------------------------------------------------------ #include "stdafx.h" #include #include #include "triedit.h" #include "document.h" #include "privcid.h" #include "dispatch.h" #include "trace.h" #include "undo.h" /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::DragEnter (IDropTarget method) // // In design mode, accept drags that originate within Trident. Allow unlocked // 2D positioned elements to be dragged using a dashed outline as a drag // rectangle. If TriEdit's constrained dragging mode has been enabled using // the Constrain method then the drag will be constrained to points which are // even multiples of the values in m_ptConstrain. // STDMETHODIMP CTriEditDocument::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { HRESULT hr = GetElement(TRUE /* fInDragDrop */); m_fLocked = FALSE; m_eDirection = CONSTRAIN_NONE; if (SUCCEEDED(hr) && m_pihtmlElement && SUCCEEDED(hr=GetTridentWindow())) { BOOL f2D = FALSE; LONG lWidth; LONG lHeight; IHTMLElement* pihtmlElementParent=NULL; HBITMAP hbmp; _ASSERTE(m_pihtmlStyle); if (IsDesignMode() && //Are we in design mode? m_pihtmlStyle && //abort if don't have style IsDragSource() && //abort if Trident isn't source of drag SUCCEEDED(Is2DElement(m_pihtmlElement, &f2D)) && f2D && SUCCEEDED(IsLocked(m_pihtmlElement, &m_fLocked)) && !m_fLocked && SUCCEEDED(GetScrollPosition()) && SUCCEEDED(GetElementPosition(m_pihtmlElement, &m_rcElement))) { //first, let's get a pattern brush to use for the move rectangle hbmp = LoadBitmap(_Module.GetModuleInstance(), (LPCWSTR)IDR_FEEDBACKRECTBMP); _ASSERTE(hbmp); m_hbrDragRect = CreatePatternBrush(hbmp); _ASSERTE(m_hbrDragRect); DeleteObject(hbmp); ::SetRect(&m_rcElementParent, 0, 0, 0, 0); hr = m_pihtmlElement->get_offsetParent(&pihtmlElementParent); if (SUCCEEDED(hr) && pihtmlElementParent) { GetElementPosition(pihtmlElementParent, &m_rcElementParent); } SAFERELEASE(pihtmlElementParent); lWidth = m_rcElement.right - m_rcElement.left; lHeight = m_rcElement.bottom - m_rcElement.top; //this is where we'll initially draw the drag rectangle m_rcDragRect = m_rcElementOrig = m_rcElement; //convert clicked point to client coordinates m_ptClickLast.x = pt.x; m_ptClickLast.y = pt.y; ScreenToClient(m_hwndTrident, &m_ptClickLast); //save point in doc coordinates where clicked. m_ptClickOrig = m_ptClickLast; m_ptClickOrig.x += m_ptScroll.x; m_ptClickOrig.y += m_ptScroll.y; if (m_fConstrain) { m_ptConstrain.x = m_rcElement.left; m_ptConstrain.y = m_rcElement.top; } #define BORDER_WIDTH 7 if (m_ptClickOrig.x < (m_rcDragRect.left - BORDER_WIDTH)) { m_rcDragRect.left = m_ptClickOrig.x; m_rcDragRect.right = m_rcDragRect.left + lWidth; } else if (m_ptClickOrig.x > (m_rcDragRect.right + BORDER_WIDTH)) { m_rcDragRect.right = m_ptClickOrig.x; m_rcDragRect.left = m_rcDragRect.right - lWidth; } if (m_ptClickOrig.y < (m_rcDragRect.top - BORDER_WIDTH)) { m_rcDragRect.top = m_ptClickOrig.y; m_rcDragRect.bottom = m_rcDragRect.top + lHeight; } else if (m_ptClickOrig.y > (m_rcDragRect.bottom + BORDER_WIDTH)) { m_rcDragRect.bottom = m_ptClickOrig.y; m_rcDragRect.top = m_rcDragRect.bottom - lHeight; } m_rcElement = m_rcDragRect; //Trace("DragEnter: m_rcElement(%d,%d,%d,%d)", m_rcElement.left, m_rcElement.top, m_rcElement.right, m_rcElement.bottom); //Trace("DragEnter: m_rcDragRect(%d,%d,%d,%d)", m_rcDragRect.left, m_rcDragRect.top, m_rcDragRect.right, m_rcDragRect.bottom); //Trace("DragEnter: m_ptClickLast(%d,%d)", m_ptClickLast.x, m_ptClickLast.y); //Trace("DragEnter: m_ptClickOrig(%d,%d)", m_ptClickOrig.x, m_ptClickOrig.y); //now draw the selection rect Draw2DDragRect(TRUE); *pdwEffect = DROPEFFECT_MOVE; hr = S_OK; } else if (!m_fLocked) { //something is hosed. just bail ReleaseElement(); } } if (!m_pihtmlElement && NULL != m_pDropTgtTrident) { hr = m_pDropTgtTrident->DragEnter(pDataObject, grfKeyState, pt, pdwEffect); } return hr; } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::DragOver (IDropTarget method) // // Provide feedback during a drag, updating the drag rectangle, and scrolling // the document as needed. STDMETHODIMP CTriEditDocument::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { HRESULT hr = E_UNEXPECTED; POINT ptClient; if (m_pihtmlElement && !m_fLocked && SUCCEEDED(GetScrollPosition())) //we are handling the drag-drop { ptClient.x = pt.x; ptClient.y = pt.y; ScreenToClient(m_hwndTrident, &ptClient); // scroll if required if (S_OK == DragScroll(ptClient)) { *pdwEffect = DROPEFFECT_MOVE | DROPEFFECT_SCROLL; } else { if (ptClient.x != m_ptClickLast.x || ptClient.y != m_ptClickLast.y) { //update the last click position m_ptClickLast.x = ptClient.x; m_ptClickLast.y = ptClient.y; //Trace("DragOver: m_ptClickLast(%d,%d)", m_ptClickLast.x, m_ptClickLast.y); //erase the move rectangle Draw2DDragRect(FALSE); ConstrainXY(&ptClient); SnapToGrid(&ptClient); //redraw the move rectangle Draw2DDragRect(TRUE); } *pdwEffect = DROPEFFECT_MOVE; } hr = S_OK; } if (!m_pihtmlElement && NULL != m_pDropTgtTrident) { hr = m_pDropTgtTrident->DragOver(grfKeyState, pt, pdwEffect); } return hr; } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::DragLeave (IDropTarget method) // // If currently dragging, erase the drag rectangle. // STDMETHODIMP CTriEditDocument::DragLeave() { HRESULT hr = E_UNEXPECTED; if (m_pihtmlElement && !m_fLocked) { //erase the move rectangle Draw2DDragRect(FALSE); if (m_hbrDragRect) { DeleteObject(m_hbrDragRect); m_hbrDragRect = NULL; } hr = S_OK; } else if (!m_pihtmlElement && NULL != m_pDropTgtTrident) { hr = m_pDropTgtTrident->DragLeave(); } ReleaseElement(); return hr; } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::Drop (IDropTarget method) // // After a successful drag of an unlocked element, erase the drag rectangle // and then handle the actual drop by moving or creating an item. Newly // created items will be 2D positionable. // STDMETHODIMP CTriEditDocument::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { HRESULT hr = E_UNEXPECTED; if (m_pihtmlElement && !m_fLocked) { _ASSERTE(m_pihtmlElement); _ASSERTE(m_pihtmlStyle); //erase the move rectangle Draw2DDragRect(FALSE); if (m_hbrDragRect) { DeleteObject(m_hbrDragRect); m_hbrDragRect = NULL; } if (m_pihtmlStyle) { POINT ptOrig, ptMove; m_rcDragRect.left = m_rcDragRect.left - m_rcElementParent.left; m_rcDragRect.top = m_rcDragRect.top - m_rcElementParent.top; m_rcDragRect.right = m_rcDragRect.right - m_rcElementParent.right; m_rcDragRect.bottom = m_rcDragRect.bottom - m_rcElementParent.bottom; ptOrig.x = m_rcElementOrig.left; ptOrig.y = m_rcElementOrig.top; ptMove.x = m_rcDragRect.left; ptMove.y = m_rcDragRect.top; CUndoDrag* pUndoDrag = new CUndoDrag(m_pihtmlStyle, ptOrig, ptMove); if (pUndoDrag) //constructor sets m_cRef=1 { hr = AddUndoUnit(m_pUnkTrident, pUndoDrag); _ASSERTE(SUCCEEDED(hr)); pUndoDrag->Release(); } m_pihtmlStyle->put_pixelLeft(m_rcDragRect.left); m_pihtmlStyle->put_pixelTop(m_rcDragRect.top); } //cleanup hr = S_OK; } if (!m_pihtmlElement && NULL != m_pDropTgtTrident) { hr = m_pDropTgtTrident->Drop(pDataObject, grfKeyState, pt, pdwEffect); // The following is to workaround a Trident bug where they don't // set the focus to their window upon the drop if (S_OK == hr) { CComPtr pInPlaceSite; CComPtr pInPlaceFrame; CComPtr pInPlaceWindow; RECT posRect, clipRect; OLEINPLACEFRAMEINFO frameInfo; HWND hwnd, hwndFrame; if (S_OK == m_pClientSiteHost->QueryInterface(IID_IOleInPlaceSite, (void **)&pInPlaceSite)) { _ASSERTE(NULL != pInPlaceSite.p); if (S_OK == pInPlaceSite->GetWindowContext(&pInPlaceFrame, &pInPlaceWindow, &posRect, &clipRect, &frameInfo)) { if (NULL != pInPlaceWindow.p) pInPlaceWindow->GetWindow(&hwnd); else { _ASSERTE(NULL != pInPlaceFrame.p); pInPlaceFrame->GetWindow(&hwnd); } // We need to walk up the parent chain till we find a frame window to work around a Vegas bug // Note that this is generic enough to do the right thing for all of our clients hwndFrame = hwnd; do { if (GetWindowLong(hwndFrame, GWL_STYLE) & WS_THICKFRAME) break; hwndFrame = GetParent(hwndFrame); } while (hwndFrame); SetFocus(hwndFrame && IsWindow(hwndFrame) ? hwndFrame : hwnd); } } } // Handle 2d drop mode here if (S_OK == hr && !IsDragSource()) { BOOL f2DCapable = FALSE; BOOL f2D = FALSE; GetElement(); // we do the following if we are in 2DDropMode and the element is 2DCapable // and the element is not already 2D or a DTC if (m_f2dDropMode && m_pihtmlElement && SUCCEEDED(Is2DCapable(m_pihtmlElement, &f2DCapable)) && f2DCapable && SUCCEEDED(Is2DElement(m_pihtmlElement, &f2D)) && !f2D && FAILED(IsElementDTC(m_pihtmlElement))) { HRESULT hr; POINT ptClient; ptClient.x = pt.x; ptClient.y = pt.y; if (SUCCEEDED(hr = CalculateNewDropPosition(&ptClient))) hr = Make2DElement(m_pihtmlElement, &ptClient); else hr = Make2DElement(m_pihtmlElement); _ASSERTE(SUCCEEDED(hr)); } if (m_pihtmlElement) { BOOL f2D = FALSE; VARIANT var; POINT ptClient; ptClient.x = pt.x; ptClient.y = pt.y; if (SUCCEEDED(Is2DElement(m_pihtmlElement, &f2D)) && f2D) { if (SUCCEEDED(CalculateNewDropPosition(&ptClient))) { IHTMLElement *pihtmlElementParent = NULL; m_pihtmlElement->get_offsetParent(&pihtmlElementParent); if(pihtmlElementParent) { RECT rcParent; if (SUCCEEDED(GetElementPosition(pihtmlElementParent, &rcParent))) { m_pihtmlStyle->put_pixelLeft(ptClient.x - rcParent.left); m_pihtmlStyle->put_pixelTop(ptClient.y - rcParent.top); } SAFERELEASE(pihtmlElementParent); } } VariantInit(&var); var.vt = VT_I4; var.lVal = 0; m_pihtmlStyle->put_zIndex(var); AssignZIndex(m_pihtmlElement, MADE_ABSOLUTE); } } } } ReleaseElement(); return hr; } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::GetElement // // Fetch the current Trident element and its style into m_pihtmlElement and // m_pihtmlStyle, respectively. If currently in mid-drag-drop (as indicated // by fInDragDrop) then do not accept an HTML element of type "Text" as // the currrent element. Returns S_OK or a Trident error. // HRESULT CTriEditDocument::GetElement(BOOL fInDragDrop) { IHTMLDocument2* pihtmlDoc2=NULL; IHTMLSelectionObject* pihtmlSelObj=NULL; IHTMLTxtRange* pihtmlTxtRange=NULL; IHTMLControlRange* pihtmlControlRange=NULL; IHTMLElement* pihtmlBodyElement=NULL; IUnknown* punkBody=NULL; IUnknown* punkElement=NULL; IDispatch* pidisp=NULL; BSTR bstrType=NULL; ReleaseElement(); //cleanup just in case... _ASSERTE(m_pUnkTrident); HRESULT hr = GetDocument(&pihtmlDoc2); if (FAILED(hr)) goto CleanUp; hr = pihtmlDoc2->get_selection(&pihtmlSelObj); if (FAILED(hr)) goto CleanUp; _ASSERTE(pihtmlSelObj); hr = pihtmlSelObj->get_type(&bstrType); _ASSERTE(SUCCEEDED(hr)); if (FAILED(hr) || !bstrType || (fInDragDrop && _wcsicmp(bstrType, L"Text")==0)) goto CleanUp; hr = pihtmlSelObj->createRange(&pidisp); if (FAILED(hr) || !pidisp) goto CleanUp; hr = pidisp->QueryInterface(IID_IHTMLTxtRange, (LPVOID*)&pihtmlTxtRange); if (SUCCEEDED(hr)) { _ASSERTE(pihtmlTxtRange); hr = pihtmlTxtRange->parentElement(&m_pihtmlElement); goto CleanUp; } hr = pidisp->QueryInterface(IID_IHTMLControlRange, (LPVOID*)&pihtmlControlRange); if (SUCCEEDED(hr)) { _ASSERTE(pihtmlControlRange); hr = pihtmlControlRange->commonParentElement(&m_pihtmlElement); } CleanUp: hr = E_FAIL; if (m_pihtmlElement) { //get the body element hr = pihtmlDoc2->get_body(&pihtmlBodyElement); _ASSERTE(SUCCEEDED(hr)); if (SUCCEEDED(hr)) { //get their IUnknowns hr = pihtmlBodyElement->QueryInterface(IID_IUnknown, (LPVOID*)&punkBody); _ASSERTE(SUCCEEDED(hr)); hr = m_pihtmlElement->QueryInterface(IID_IUnknown, (LPVOID*)&punkElement); _ASSERTE(SUCCEEDED(hr)); //If they're equivalent, the body element is the current element //and we don't want it. if (punkBody == punkElement) { hr = E_FAIL; } } // VID98 bug 2647: if type is none, don't bother to cache style. // This is to workaround trident crash bug if (SUCCEEDED(hr) && bstrType && _wcsicmp(bstrType, L"None")!=0) { hr = m_pihtmlElement->get_style(&m_pihtmlStyle); _ASSERTE(SUCCEEDED(hr)); _ASSERTE(m_pihtmlStyle); } if (FAILED(hr) || !m_pihtmlStyle) { ReleaseElement(); } hr = S_OK; } SAFERELEASE(pihtmlDoc2); SAFERELEASE(pihtmlSelObj); SAFERELEASE(pidisp); SAFERELEASE(pihtmlTxtRange); SAFERELEASE(pihtmlControlRange); SAFERELEASE(pihtmlBodyElement); SAFERELEASE(punkBody); SAFERELEASE(punkElement); SysFreeString(bstrType); return hr; } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::ReleaseElement // // Release any cached reference to the current Trident element and its // associated style. No return value. // void CTriEditDocument::ReleaseElement(void) { SAFERELEASE(m_pihtmlElement); SAFERELEASE(m_pihtmlStyle); } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::Draw2DDragRect // // After giving the drag-drop handler host a chance to draw the drag rectangle, // draw the rectangle if the handler choose not to do so. No return value. // void CTriEditDocument::Draw2DDragRect(BOOL fDraw) { RECT rect = m_rcDragRect; // S_FALSE means that the host has already drawn its own feedback if (m_pDragDropHandlerHost && m_pDragDropHandlerHost->DrawDragFeedback(&rect) == S_FALSE) return; if ((fDraw == m_fDragRectVisible) || (NULL == m_hwndTrident) || (NULL == m_hbrDragRect)) return; HDC hdc = GetDC(m_hwndTrident); _ASSERTE(hdc); HBRUSH hbrOld = (HBRUSH)SelectObject(hdc, m_hbrDragRect); _ASSERTE(hbrOld); //BUGS:M3-2723\The Drag Rectangle Must be at Least 8x8 pixels LONG lWidth = max((rect.right - rect.left), 16); LONG lHeight = max((rect.bottom - rect.top), 16); SetWindowOrgEx(hdc, m_ptScroll.x, m_ptScroll.y, NULL); //A Value of 2 is added to the rect's left and top in all the following PatBlt function //to work around a rounding off bug caused by trident. PatBlt( hdc, rect.left + 2, rect.top + 2, lWidth, 1, PATINVERT); PatBlt( hdc, rect.left + 2, rect.top + lHeight + 1, //(2 - 1) lWidth, 1, PATINVERT); PatBlt( hdc, rect.left + 2, rect.top + 3,//(2 + 1) 1, lHeight - (2 * 1), PATINVERT); PatBlt( hdc, rect.left + lWidth + 1 /*(2 - 1)*/, rect.top + 3, //(2 + 1) 1, lHeight - (2 * 1), PATINVERT); m_fDragRectVisible = !m_fDragRectVisible; SelectObject(hdc, hbrOld); ReleaseDC(m_hwndTrident, hdc); } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::GetScrollPosition // // Get the Trident document's scroll position and store it in m_ptScroll. // Return S_OK or a Trident error code. // HRESULT CTriEditDocument::GetScrollPosition(void) { IHTMLDocument2* pihtmlDoc2=NULL; IHTMLTextContainer* pihtmlTextContainer=NULL; IHTMLElement* pihtmlElement=NULL; HRESULT hr = E_FAIL; _ASSERTE(m_pUnkTrident); if (SUCCEEDED(GetDocument(&pihtmlDoc2))) { if (SUCCEEDED(pihtmlDoc2->get_body(&pihtmlElement))) { _ASSERTE(pihtmlElement); if (pihtmlElement) { if (SUCCEEDED(pihtmlElement->QueryInterface(IID_IHTMLTextContainer, (LPVOID*)&pihtmlTextContainer))) { _ASSERTE(pihtmlTextContainer); if (pihtmlTextContainer) { hr = pihtmlTextContainer->get_scrollLeft(&m_ptScroll.x); _ASSERTE(SUCCEEDED(hr)); hr = pihtmlTextContainer->get_scrollTop(&m_ptScroll.y); _ASSERTE(SUCCEEDED(hr)); hr = S_OK; } } } } } SAFERELEASE(pihtmlDoc2); SAFERELEASE(pihtmlTextContainer); SAFERELEASE(pihtmlElement); return hr; } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::DragScroll // // Scroll the Trident document so as to make the given point visible. If a // drag rectangle is visible it will be erased before any scrolling occurs; // the caller is responsible for redrawing the rectangle. Returns S_OK if the // document was scrolled, S_FALSE if not scrolling was required, or a // Trident error. // #define nScrollInset 5 HRESULT CTriEditDocument::DragScroll(POINT pt) { RECT rectClient, rect; long x = 0, y = 0; IHTMLDocument2* pihtmlDoc2=NULL; IHTMLWindow2* pihtmlWindow2=NULL; GetClientRect(m_hwndTrident, &rectClient); rect = rectClient; InflateRect(&rect, -nScrollInset, -nScrollInset); if (PtInRect(&rectClient, pt) && !PtInRect(&rect, pt)) { // determine direction of scroll along both X & Y axis if (pt.x < rect.left) x = -nScrollInset; else if (pt.x >= rect.right) x = nScrollInset; if (pt.y < rect.top) y = -nScrollInset; else if (pt.y >= rect.bottom) y = nScrollInset; } if (x == 0 && y == 0) // no scrolling required return S_FALSE; _ASSERTE(m_pUnkTrident); if (SUCCEEDED(GetDocument(&pihtmlDoc2))) { _ASSERTE(pihtmlDoc2); if (SUCCEEDED(pihtmlDoc2->get_parentWindow(&pihtmlWindow2))) { _ASSERTE(pihtmlWindow2); // erase move rectangle before scrolling Draw2DDragRect(FALSE); pihtmlWindow2->scrollBy(x,y); } } SAFERELEASE(pihtmlDoc2); SAFERELEASE(pihtmlWindow2); return S_OK; } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::IsDragSource // // Return TRUE if the current OLE drag-drop was originated by Trident, or // FALSE otherwise. // BOOL CTriEditDocument::IsDragSource(void) { BOOL fDragSource = FALSE; HRESULT hr; VARIANT var; if (m_pUnkTrident) { IOleCommandTarget* pioleCmdTarget; if (SUCCEEDED(m_pUnkTrident->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&pioleCmdTarget))) { _ASSERTE(pioleCmdTarget); if (pioleCmdTarget) { VariantInit(&var); var.vt = VT_BOOL; var.boolVal = FALSE; hr = pioleCmdTarget->Exec( &CMDSETID_Forms3, IDM_SHDV_ISDRAGSOURCE, MSOCMDEXECOPT_DONTPROMPTUSER, NULL, &var ); _ASSERTE(SUCCEEDED(hr)); fDragSource = (var.boolVal) ? TRUE:FALSE; pioleCmdTarget->Release(); } } } return fDragSource; } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::ConstrainXY // // If TriEdit's constrained dragging mode is enabled, constrain the // rectangle of the current element (m_rcElement) vis-a-vis the given // point according to the current constraint direction, first computing // the constraint direction if necessary. Return S_OK. // HRESULT CTriEditDocument::ConstrainXY(LPPOINT lppt) //pt is in client coordinates { POINT ptRel; if (m_fConstrain) { if (CONSTRAIN_NONE == m_eDirection) { ptRel.x = (lppt->x + m_ptScroll.x) - m_ptClickOrig.x; ptRel.y = (lppt->y + m_ptScroll.y) - m_ptClickOrig.y; if ((ptRel.x && !ptRel.y) || (abs(ptRel.x) > abs(ptRel.y))) m_eDirection = CONSTRAIN_HORIZONTAL; else if ((!ptRel.y && ptRel.y) || (abs(ptRel.y) > abs(ptRel.x))) m_eDirection = CONSTRAIN_VERTICAL; else m_eDirection = CONSTRAIN_HORIZONTAL; if (m_eDirection == CONSTRAIN_VERTICAL) { LONG lWidth = m_rcElement.right - m_rcElement.left; m_ptClickOrig.x = m_rcElement.left = m_ptConstrain.x; m_rcElement.right = m_rcElement.left + lWidth; } else { LONG lHeight = m_rcElement.bottom - m_rcElement.top; m_ptClickOrig.y = m_rcElement.top = m_ptConstrain.y; m_rcElement.bottom = m_rcElement.top + lHeight; } } switch(m_eDirection) { case CONSTRAIN_HORIZONTAL: lppt->y = (m_ptClickOrig.y - m_ptScroll.y); break; case CONSTRAIN_VERTICAL: lppt->x = (m_ptClickOrig.x - m_ptScroll.x); break; } } return S_OK; } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::SnapToGrid // // Snap the appropriate edge of the current HTML element (m_rcElement) to the // given point, modulo the current TriEdit grid setting. Return S_OK. // HRESULT CTriEditDocument::SnapToGrid(LPPOINT lppt) //pt is in client coordinates { POINT ptRel; POINT ptDoc; _ASSERTE(lppt); //determine relative movement ptRel.x = (lppt->x + m_ptScroll.x) - m_ptClickOrig.x; ptRel.y = (lppt->y + m_ptScroll.y) - m_ptClickOrig.y; ptDoc.x = m_rcElement.left - m_rcElementParent.left + ptRel.x; ptDoc.y = m_rcElement.top - m_rcElementParent.top + ptRel.y; if (ptRel.x < 0) //LEFT { if (ptDoc.x % m_ptAlign.x) ptDoc.x -= (ptDoc.x % m_ptAlign.x); else ptDoc.x -= m_ptAlign.x; } else if (ptRel.x > 0) //RIGHT { if (ptDoc.x % m_ptAlign.x) ptDoc.x += m_ptAlign.x - (ptDoc.x % m_ptAlign.x); else ptDoc.x += m_ptAlign.x; } if (ptRel.y < 0) //UP { if (ptDoc.y % m_ptAlign.y) ptDoc.y -= (ptDoc.y % m_ptAlign.y); else ptDoc.y -= m_ptAlign.y; } else if (ptRel.y > 0) //DOWN { if (ptDoc.y % m_ptAlign.y) ptDoc.y += m_ptAlign.y - (ptDoc.y % m_ptAlign.y); else ptDoc.y += m_ptAlign.y; } m_rcDragRect.left = m_rcElementParent.left + ptDoc.x; m_rcDragRect.top = m_rcElementParent.top + ptDoc.y; m_rcDragRect.right = m_rcDragRect.left + (m_rcElement.right - m_rcElement.left); m_rcDragRect.bottom = m_rcDragRect.top + (m_rcElement.bottom - m_rcElement.top); return S_OK; } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::IsDesignMode // // Return TRUE if Trident is in design (edit) mode, or FALSE if it is in // browse mode. // BOOL CTriEditDocument::IsDesignMode(void) { HRESULT hr; OLECMD olecmd; olecmd.cmdID = IDM_EDITMODE; hr = m_pCmdTgtTrident->QueryStatus(&CMDSETID_Forms3, 1, &olecmd, NULL); return (SUCCEEDED(hr) && (olecmd.cmdf & OLECMDF_LATCHED)); } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::GetElementPosition // // Return (under prc) the position of the given HTML element in document // coordinates. Return S_OK or a Trident error code as the return value. // HRESULT CTriEditDocument::GetElementPosition(IHTMLElement* pihtmlElement, LPRECT prc) { IHTMLElement* pelem = NULL; IHTMLElement* pelemNext = NULL; POINT ptExtent; HRESULT hr; _ASSERTE(pihtmlElement && prc); if(!pihtmlElement || !prc) return E_POINTER; if(FAILED(pihtmlElement->get_offsetLeft(&prc->left))) return(E_FAIL); if(FAILED(pihtmlElement->get_offsetTop(&prc->top))) return(E_FAIL); hr = pihtmlElement->get_offsetParent(&pelemNext); while (SUCCEEDED(hr) && pelemNext) { POINT pt; if(FAILED(hr = pelemNext->get_offsetLeft(&pt.x))) goto QuickExit; if(FAILED(hr = pelemNext->get_offsetTop(&pt.y))) goto QuickExit; prc->left += pt.x; prc->top += pt.y; pelem = pelemNext; pelemNext = NULL; hr = pelem->get_offsetParent(&pelemNext); SAFERELEASE(pelem); } if (FAILED(hr = pihtmlElement->get_offsetWidth(&ptExtent.x))) goto QuickExit; if (FAILED(hr = pihtmlElement->get_offsetHeight(&ptExtent.y))) goto QuickExit; prc->right = prc->left + ptExtent.x; prc->bottom = prc->top + ptExtent.y; QuickExit: _ASSERTE(SUCCEEDED(hr)); SAFERELEASE(pelem); SAFERELEASE(pelemNext); return hr; } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::GetTridentWindow // // Fetch the IOleWindow interface of the Trident instance in to m_hwndTrident. // Return S_OK or the Trident error code. // STDMETHODIMP CTriEditDocument::GetTridentWindow() { LPOLEWINDOW piolewinTrident; HRESULT hr = E_FAIL; if( m_pOleObjTrident && SUCCEEDED(hr = m_pOleObjTrident->QueryInterface(IID_IOleWindow, (LPVOID*)&piolewinTrident))) { m_hwndTrident = NULL; hr = piolewinTrident->GetWindow(&m_hwndTrident); _ASSERTE(m_hwndTrident != NULL); piolewinTrident->Release(); } _ASSERTE(SUCCEEDED(hr)); return hr; } /////////////////////////////////////////////////////////////////////////////// // // CTriEditDocument::CalculateNewDropPosition // // Adjust the given point to adjust for the fact that the Trident document may // be scrolled. Return S_OK or a Trident error code. HRESULT CTriEditDocument::CalculateNewDropPosition(POINT *pt) { HRESULT hr = E_FAIL; if (SUCCEEDED(hr = GetTridentWindow()) && ScreenToClient(m_hwndTrident, pt) && SUCCEEDED(hr = GetScrollPosition())) { pt->x += m_ptScroll.x; pt->y += m_ptScroll.y; } return hr; }