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

//------------------------------------------------------------------------------
// 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 <ocidl.h>
#include <string.h>
#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<IOleInPlaceSite> pInPlaceSite;
CComPtr<IOleInPlaceFrame> pInPlaceFrame;
CComPtr<IOleInPlaceUIWindow> 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;
}