windows-nt/Source/XPSP1/NT/shell/shdocvw/airesize.cpp
2020-09-26 16:20:57 +08:00

1313 lines
35 KiB
C++

#include "priv.h"
#include <iehelpid.h>
#include <pstore.h>
#include "hlframe.h"
#include "shldisp.h"
#include "opsprof.h"
#include "resource.h"
#include <mluisupp.h>
#include "htmlstr.h"
#include "airesize.h"
#include "mshtmcid.h"
#include "util.h"
#include "winuser.h"
//////////////////////////////////////////////////////////////////////////////////
//
// filename: airesize.cpp
//
// description: implements the autoimageresize feature
//
// notes:
//
// history: 03.07.2001 by jeffdav
//
//////////////////////////////////////////////////////////////////////////////////
extern HINSTANCE g_hinst;
#define TF_AIRESIZE TF_CUSTOM2
CAutoImageResizeEventSinkCallback::EventSinkEntry CAutoImageResizeEventSinkCallback::EventsToSink[] =
{
{ EVENT_MOUSEOVER, L"onmouseover", L"mouseover" },
{ EVENT_MOUSEOUT, L"onmouseout", L"mouseout" },
{ EVENT_SCROLL, L"onscroll", L"scroll" },
{ EVENT_RESIZE, L"onresize", L"resize" },
{ EVENT_BEFOREPRINT, L"onbeforeprint", L"beforeprint"},
{ EVENT_AFTERPRINT, L"onafterprint", L"afterprint" }
};
// autoimage resize states
enum
{
AIRSTATE_BOGUS = 0,
AIRSTATE_INIT,
AIRSTATE_NORMAL,
AIRSTATE_RESIZED,
AIRSTATE_WAITINGTORESIZE
};
// button states
enum
{
AIRBUTTONSTATE_BOGUS = 0,
AIRBUTTONSTATE_HIDDEN,
AIRBUTTONSTATE_VISIBLE,
AIRBUTTONSTATE_WAITINGTOSHOW,
AIRBUTTONSTATE_NOBUTTON
};
////////////////////////////////////////////////////////////////////////////
// QI, AddRef, Release:
STDMETHODIMP CAutoImageResize::QueryInterface(REFIID riid, void **ppv)
{
*ppv = NULL;
if ((IID_IPropertyNotifySink == riid) || (IID_IUnknown == riid))
{
*ppv = (IPropertyNotifySink *)this;
}
if (*ppv)
{
((IUnknown *)*ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CAutoImageResize::AddRef(void)
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CAutoImageResize::Release(void)
{
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
//////////////////////////////////////////////////////////////////////////////
// Constructor, Destructor, Init, UnInit:
// constructor
CAutoImageResize::CAutoImageResize()
{
TraceMsg(TF_AIRESIZE, "+CAutoImageResize::CAutoImageResize");
m_airState = AIRSTATE_INIT;
m_airUsersLastChoice= AIRSTATE_BOGUS; // we don't care until the user clicks the button
m_hWndButton = NULL;
m_hWnd = NULL;
m_wndProcOld = NULL;
m_pDoc2 = NULL;
m_pEle2 = NULL;
m_pWin3 = NULL;
m_bWindowResizing = FALSE;
m_himlButtonShrink = NULL;
m_himlButtonExpand = NULL;
TraceMsg(TF_AIRESIZE, "-CAutoImageResize::CAutoImageResize");
}
// destructor
CAutoImageResize::~CAutoImageResize()
{
TraceMsg(TF_AIRESIZE, "+CAutoImageResize::~CAutoImageResize");
DestroyButton();
ATOMICRELEASE(m_pEle2);
ATOMICRELEASE(m_pDoc2);
TraceMsg(TF_AIRESIZE, "-CAutoImageResize::~CAutoImageResize");
}
HRESULT CAutoImageResize::Init(IHTMLDocument2 *pDoc2)
{
HRESULT hr = S_OK;
TraceMsg(TF_AIRESIZE, "+CAutoImageResize::Init");
ASSERT(pDoc2);
//sink things
IHTMLElement2 *pEle2 = NULL;
IHTMLElementCollection *pCollect = NULL;
IHTMLElementCollection *pSubCollect = NULL;
IDispatch *pDisp = NULL;
VARIANT TagName;
ULONG ulCount = 0;
VARIANTARG va1;
VARIANTARG va2;
IHTMLWindow3 *pWin3 = NULL;
IOleWindow *pOleWin = NULL;
// ...remember this...
m_pDoc2 = pDoc2;
pDoc2->AddRef();
// ...remember the hwnd also...
hr = m_pDoc2->QueryInterface(IID_IOleWindow,(void **)&pOleWin);
if (FAILED(hr))
goto Cleanup;
pOleWin->GetWindow(&m_hWnd);
// setup variant for finding all the IMG tags...
TagName.vt = VT_BSTR;
TagName.bstrVal = (BSTR)c_bstr_IMG;
//get all tags
hr = pDoc2->get_all(&pCollect);
if (FAILED(hr))
goto Cleanup;
//get all IMG tags
hr = pCollect->tags(TagName, &pDisp);
if (FAILED(hr))
goto Cleanup;
if (pDisp)
{
hr = pDisp->QueryInterface(IID_IHTMLElementCollection,(void **)&pSubCollect);
ATOMICRELEASE(pDisp);
}
if (FAILED(hr))
goto Cleanup;
//get IMG tag count
hr = pSubCollect->get_length((LONG *)&ulCount);
if (FAILED(hr))
goto Cleanup;
// highlander theorem: there can be only one!
// bt's corollary: there must be exactally one.
if (1 != ulCount)
goto Cleanup;
va1.vt = VT_I4;
va2.vt = VT_EMPTY;
pDisp = NULL;
va1.lVal = (LONG)0;
pSubCollect->item(va1, va2, &pDisp);
// create event sink for the image
if (!m_pSink && pDisp)
m_pSink = new CEventSink(this);
if (pDisp)
{
hr = pDisp->QueryInterface(IID_IHTMLElement2, (void **)&pEle2);
if (FAILED(hr))
goto Cleanup;
ASSERT(m_pSink);
if (m_pSink && pEle2)
{
EVENTS events[] = { EVENT_MOUSEOVER, EVENT_MOUSEOUT };
m_pSink->SinkEvents(pEle2, ARRAYSIZE(events), events);
m_pEle2=pEle2;
pEle2->AddRef();
}
ATOMICRELEASE(pEle2);
ATOMICRELEASE(pDisp);
}
// sink scroll event from the window, because it doesn't come from elements.
if (m_pSink)
{
Win3FromDoc2(m_pDoc2, &pWin3);
if (pWin3)
{
m_pWin3 = pWin3;
m_pWin3->AddRef();
EVENTS events[] = { EVENT_SCROLL, EVENT_RESIZE, EVENT_BEFOREPRINT, EVENT_AFTERPRINT };
m_pSink->SinkEvents(pWin3, ARRAYSIZE(events), events);
}
}
// end sinking things
// Init() gets called when onload fires, so the image *should* be ready
// to get adjusted, if need be...
DoAutoImageResize();
Cleanup:
ATOMICRELEASE(pCollect);
ATOMICRELEASE(pSubCollect);
ATOMICRELEASE(pWin3);
ATOMICRELEASE(pDisp);
ATOMICRELEASE(pEle2);
ATOMICRELEASE(pOleWin);
TraceMsg(TF_AIRESIZE, "-CAutoImageResize::Init");
return hr;
}
HRESULT CAutoImageResize::UnInit()
{
// Unhook regular event sink
TraceMsg(TF_AIRESIZE, "+CAutoImageResize::UnInit");
DestroyButton();
if (m_pSink)
{
if (m_pWin3)
{
EVENTS events[] = { EVENT_SCROLL, EVENT_RESIZE, EVENT_BEFOREPRINT, EVENT_AFTERPRINT };
m_pSink->UnSinkEvents(m_pWin3, ARRAYSIZE(events), events);
SAFERELEASE(m_pWin3);
}
m_pSink->SetParent(NULL);
ATOMICRELEASE(m_pSink);
}
SAFERELEASE(m_pEle2);
SAFERELEASE(m_pDoc2);
TraceMsg(TF_AIRESIZE, "-CAutoImageResize::UnInit");
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////
// AutoImageResize Functions:
HRESULT CAutoImageResize::DoAutoImageResize()
{
HRESULT hr = S_OK;
IHTMLImgElement *pImgEle = NULL;
LONG lHeight = 0;
LONG lWidth = 0;
LONG lNewHeight = 0;
LONG lNewWidth = 0;
LONG lScrHt = 0;
LONG lScrWd = 0;
RECT rcBrowserWnd;
ASSERT(m_pEle2);
// get an IHTMLImgElement from the IHTMLElement cached...
hr = m_pEle2->QueryInterface(IID_IHTMLImgElement, (void **)&pImgEle);
if (FAILED(hr) || !pImgEle)
goto Cleanup;
// get the current dimensions
if (FAILED(pImgEle->get_height(&lHeight)) || FAILED(pImgEle->get_width(&lWidth)))
goto Cleanup;
// if this is the first time through, we need to take care of some init stuff
if (AIRSTATE_INIT == m_airState)
{
// cache orig dimensions
m_airOrigSize.x = lWidth;
m_airOrigSize.y = lHeight;
// INIT done, promote to NORMAL
m_airState = AIRSTATE_NORMAL;
}
// check to see if we are being called because the user is resizing the window
// and then massage the state as necessary.
if (m_bWindowResizing)
{
m_airState = AIRSTATE_NORMAL;
}
switch (m_airState)
{
case AIRSTATE_NORMAL:
// how big is the window?
if (GetClientRect(m_hWnd, &rcBrowserWnd))
{
lScrHt = rcBrowserWnd.bottom - rcBrowserWnd.top;
lScrWd = rcBrowserWnd.right - rcBrowserWnd.left;
// is the image bigger then the window?
if (lScrWd < lWidth)
m_airState=AIRSTATE_WAITINGTORESIZE;
if (lScrHt < lHeight)
m_airState=AIRSTATE_WAITINGTORESIZE;
}
else
goto Cleanup;
// if the window is resizing, we may need to expand the image, so massage the state again...
// (there is a check later on to make sure we don't expand too far...)
if (m_bWindowResizing)
{
m_airState = AIRSTATE_WAITINGTORESIZE;
}
// image didn't fit, so we must resize now
if (AIRSTATE_WAITINGTORESIZE == m_airState)
{
// calculate new size:
if (MulDiv(lWidth,1000,lScrWd) < MulDiv(lHeight,1000,lScrHt))
{
lNewHeight = lScrHt-AIR_SCREEN_CONSTANTY;
lNewWidth = MulDiv(lNewHeight,m_airOrigSize.x,m_airOrigSize.y);
}
else
{
lNewWidth = lScrWd-AIR_SCREEN_CONSTANTX;
lNewHeight = MulDiv(lNewWidth, m_airOrigSize.y, m_airOrigSize.x);
}
// we don't ever want to resize to be LARGER then the original...
if ((lNewHeight > m_airOrigSize.y) || (lNewWidth > m_airOrigSize.x))
{
if (m_bWindowResizing)
{
// restore orig size cause it should fit and turn off the button
lNewHeight = m_airOrigSize.y;
lNewWidth = m_airOrigSize.x;
m_airButtonState = AIRBUTTONSTATE_NOBUTTON;
}
else
goto Cleanup;
}
if (FAILED(pImgEle->put_height(lNewHeight)) || FAILED(pImgEle->put_width(lNewWidth)))
{
goto Cleanup;
}
else
{
m_airState=AIRSTATE_RESIZED;
if (AIRBUTTONSTATE_VISIBLE == m_airButtonState)
{
// reposition button
HideButton();
ShowButton();
}
}
}
else
{
// It fit in the browser window so we don't need to do any work yet...
// If they resize the window or something we need to check again...
m_airButtonState=AIRBUTTONSTATE_NOBUTTON;
}
break;
case AIRSTATE_RESIZED:
// restore the image to its normal size
if (FAILED(pImgEle->put_height(m_airOrigSize.y)) ||
FAILED(pImgEle->put_width (m_airOrigSize.x)))
{
goto Cleanup;
}
else
{
m_airState=AIRSTATE_NORMAL;
if (AIRBUTTONSTATE_VISIBLE == m_airButtonState)
{
// reposition button
HideButton();
ShowButton();
}
}
break;
case AIRSTATE_WAITINGTORESIZE:
// we should never be in this state at this time!
ASSERT(m_airState!=AIRSTATE_WAITINGTORESIZE);
break;
default:
break;
}
Cleanup:
ATOMICRELEASE(pImgEle);
return hr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Timer Proc:
LRESULT CALLBACK CAutoImageResize::s_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CAutoImageResize* pThis = (CAutoImageResize*)GetWindowPtr(hWnd, GWLP_USERDATA);
TraceMsg(TF_AIRESIZE, "+CAutoImageResize::s_WndProc hWnd=%x, pThis=%p", hWnd, pThis);
HRESULT hr = S_OK;
IOleCommandTarget *pOleCommandTarget = NULL;
UINT iToolTip = NULL;
switch (uMsg)
{
case WM_SIZE:
if (!pThis)
break;
SetWindowPos(pThis->m_hWndButton, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOZORDER | SWP_NOACTIVATE);
break;
case WM_ERASEBKGND:
if (!pThis)
break;
{
RECT rc;
HBRUSH hb = GetSysColorBrush(COLOR_3DFACE);
GetClientRect(pThis->m_hWndButton, &rc);
FillRect((HDC)wParam, &rc, hb);
return TRUE;
}
case WM_COMMAND:
if (!pThis)
break;
switch(LOWORD(wParam))
{
case IDM_AIR_BUTTON:
if (AIRSTATE_NORMAL == pThis->m_airState)
{
pThis->m_airUsersLastChoice = AIRSTATE_RESIZED;
}
else if (AIRSTATE_RESIZED == pThis->m_airState)
{
pThis->m_airUsersLastChoice = AIRSTATE_NORMAL;
}
pThis->DoAutoImageResize();
break;
}
break;
case WM_NOTIFY: // tooltips...
if (!pThis)
break;
switch (((LPNMHDR)lParam)->code)
{
case TTN_NEEDTEXT:
{
if (AIRSTATE_NORMAL == pThis->m_airState)
{
iToolTip = IDS_AIR_SHRINK;
}
else if (AIRSTATE_RESIZED == pThis->m_airState)
{
iToolTip = IDS_AIR_EXPAND;
}
LPTOOLTIPTEXT lpToolTipText;
TCHAR szBuf[MAX_PATH];
lpToolTipText = (LPTOOLTIPTEXT)lParam;
hr = MLLoadString(iToolTip,
szBuf,
ARRAYSIZE(szBuf));
lpToolTipText->lpszText = szBuf;
break;
}
}
break;
case WM_SETTINGCHANGE:
{
pThis->DestroyButton(); // to stop wierd window distortion
break;
}
case WM_CONTEXTMENU:
{
// should we be consistant and have a turn-me-off/help context menu?
}
break;
default:
return(DefWindowProc(hWnd, uMsg, wParam, lParam));
}
TraceMsg(TF_AIRESIZE, "-CAutoImageResize::s_WndProc hWnd=%x, pThis=%p", hWnd, pThis);
return (hr);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Timer Proc:
VOID CALLBACK CAutoImageResize::s_TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
TraceMsg(TF_AIRESIZE, "+CAutoImageResize::TimerProc");
CAutoImageResize* pThis = (CAutoImageResize*)GetWindowPtr(hwnd, GWLP_USERDATA);
switch (uMsg)
{
case WM_TIMER:
KillTimer(hwnd, IDT_AIR_TIMER);
if (pThis && (AIRBUTTONSTATE_WAITINGTOSHOW == pThis->m_airButtonState))
{
// Our hover bar is waiting to be shown.
if (pThis->m_pEle2)
{
// We still have an element. Show it.
pThis->m_airButtonState = AIRBUTTONSTATE_VISIBLE;
pThis->ShowButton();
}
else
{
// Our timer popped, but we don't have an element.
pThis->HideButton();
}
}
break;
default:
break;
}
TraceMsg(TF_AIRESIZE, "-CAutoImageResize::TimerProc");
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Button Functions:
HRESULT CAutoImageResize::CreateButton()
{
HRESULT hr = S_OK;
SIZE size = {0,0};
TraceMsg(TF_AIRESIZE, "+CAutoImageResize::CreateHover, this=%p, m_airButtonState=%d", this, m_airButtonState);
InitCommonControls();
WNDCLASS wc = {0};
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpszClassName = TEXT("AutoImageResizeHost");
wc.lpfnWndProc = s_WndProc;
wc.hInstance = g_hinst;
wc.hbrBackground = HBRUSH(COLOR_BTNFACE);
RegisterClass(&wc);
if (!m_hWndButtonCont)
{
m_hWndButtonCont = CreateWindow(TEXT("AutoImageResizeHost"), TEXT(""), WS_DLGFRAME | WS_VISIBLE | WS_CHILD /*| WS_POPUP*/,
0, 0, 0, 0, m_hWnd, NULL, g_hinst, NULL);
if (!m_hWndButtonCont)
{
TraceMsg(TF_AIRESIZE | TF_WARNING, "CAutoImageResize::CreateButton, unable to create m_hWndButtonCont");
hr = E_FAIL;
goto Cleanup;
}
// setup the window callback stuff...
ASSERT(m_wndProcOld == NULL);
m_wndProcOld = (WNDPROC)SetWindowLongPtr(m_hWndButtonCont, GWLP_WNDPROC, (LONG_PTR)s_WndProc);
// pass in the this pointer so the button can call member functions
ASSERT(GetWindowPtr(m_hWndButtonCont, GWLP_USERDATA) == NULL);
SetWindowPtr(m_hWndButtonCont, GWLP_USERDATA, this);
}
// create the button
if (!m_hWndButton)
{
m_hWndButton = CreateWindow(TOOLBARCLASSNAME, TEXT(""), TBSTYLE_TOOLTIPS | CCS_NODIVIDER | TBSTYLE_FLAT | WS_VISIBLE | WS_CHILD,
0,0,0,0, m_hWndButtonCont, NULL, g_hinst, NULL);
if (!m_hWndButton)
{
TraceMsg(TF_AIRESIZE | TF_WARNING, "CAutoImageResize::CreateButton, unable to create m_hWndButton");
hr = E_FAIL;
goto Cleanup;
}
ASSERT(GetWindowPtr(m_hWndButton, GWLP_USERDATA) == NULL);
SetWindowPtr(m_hWndButton, GWLP_USERDATA, this);
// set cc version for this too, and the sizeof tbbutton struct...
SendMessage(m_hWndButton, CCM_SETVERSION, COMCTL32_VERSION, 0);
SendMessage(m_hWndButton, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
}
if (!m_himlButtonExpand)
{
m_himlButtonExpand = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_AIR_EXPAND), 32, 0, CLR_DEFAULT, IMAGE_BITMAP, LR_CREATEDIBSECTION);
if (!m_himlButtonExpand)
{
TraceMsg(TF_AIRESIZE | TF_WARNING, "CAutoImageResize::CreateButton, unable to create m_himlButtonExpand");
hr = E_FAIL;
goto Cleanup;
}
}
if (!m_himlButtonShrink)
{
m_himlButtonShrink = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_AIR_SHRINK), 32, 0, CLR_DEFAULT, IMAGE_BITMAP, LR_CREATEDIBSECTION);
if (!m_himlButtonShrink)
{
TraceMsg(TF_AIRESIZE | TF_WARNING, "CAutoImageResize::CreateButton, unable to create m_himlButtonShrink");
hr = E_FAIL;
goto Cleanup;
}
}
// set image list and hot image list
SendMessage(m_hWndButton, TB_SETIMAGELIST, 0, (LPARAM)m_himlButtonExpand);
SendMessage(m_hWndButton, TB_SETHOTIMAGELIST, 0, (LPARAM)m_himlButtonExpand);
// add the buttons
TBBUTTON tbAirButton;
tbAirButton.iBitmap = 0;
tbAirButton.idCommand = IDM_AIR_BUTTON;
tbAirButton.fsState = TBSTATE_ENABLED;
tbAirButton.fsStyle = TBSTYLE_BUTTON;
tbAirButton.dwData = 0;
tbAirButton.iString = 0;
SendMessage(m_hWndButton, TB_INSERTBUTTON, 0, (LPARAM)&tbAirButton);
Cleanup:
TraceMsg(TF_AIRESIZE, "-CAutoImageResize::CreateButton, this=%p, m_airButtonState=%d", this, m_airButtonState);
return hr;
}
HRESULT CAutoImageResize::ShowButton()
{
HRESULT hr = E_FAIL;
IHTMLRect *pRect = NULL;
LONG lLeft = 0; // these are the screen coords
LONG lRight = 0; // we get right and bottom to det size of image
LONG lTop = 0;
LONG lBottom = 0;
DWORD dwOffset = MP_GetOffsetInfoFromRegistry();
RECT rcBrowserWnd;
WORD wImage = NULL;
DWORD dw;
SIZE sz;
RECT rc;
TraceMsg(TF_AIRESIZE, "+CAutoImageResize::ShowButton, this=%p, m_airButtonState=%d", this, m_airButtonState);
ASSERT(m_pEle2);
// get the coords of the image...
if (SUCCEEDED(m_pEle2->getBoundingClientRect(&pRect)) && pRect)
{
pRect->get_left(&lLeft);
pRect->get_right(&lRight);
pRect->get_top(&lTop);
pRect->get_bottom(&lBottom);
}
else
goto Cleanup;
// make sure we are inside the browser window...
if (GetClientRect(m_hWnd, &rcBrowserWnd))
{
// if the browser window is less then a certain min size, we
// don't display the button...
if ((rcBrowserWnd.right - rcBrowserWnd.left < AIR_MIN_BROWSER_SIZE) ||
(rcBrowserWnd.bottom - rcBrowserWnd.top < AIR_MIN_BROWSER_SIZE))
goto Cleanup;
// if the browser window is larger then the image, we don't display
// the button...
if ((AIRSTATE_NORMAL == m_airState) &&
(rcBrowserWnd.left < lLeft ) &&
(rcBrowserWnd.right > lRight ) &&
(rcBrowserWnd.top < lTop ) &&
(rcBrowserWnd.bottom > lBottom))
goto Cleanup;
// adjust for scrollbars
if (lRight > rcBrowserWnd.right - AIR_SCROLLBAR_SIZE_V)
{
lRight = rcBrowserWnd.right - AIR_SCROLLBAR_SIZE_V;
}
if (lBottom > rcBrowserWnd.bottom - AIR_SCROLLBAR_SIZE_H)
{
lBottom = rcBrowserWnd.bottom - AIR_SCROLLBAR_SIZE_H;
}
}
else
goto Cleanup;
// someone tried to show the button, but it doesn't exist.
// this is ok, if we actually have an element, so fix it for them.
if (!m_hWndButtonCont && m_pEle2)
CreateButton();
// make sure the image list exists
if (!m_himlButtonShrink || !m_himlButtonExpand)
{
hr = E_FAIL;
goto Cleanup;
}
if (AIRSTATE_NORMAL == m_airState)
{
SendMessage(m_hWndButton, TB_SETIMAGELIST, 0, (LPARAM)m_himlButtonShrink);
SendMessage(m_hWndButton, TB_SETHOTIMAGELIST, 0, (LPARAM)m_himlButtonShrink);
}
else if (AIRSTATE_RESIZED == m_airState)
{
SendMessage(m_hWndButton, TB_SETIMAGELIST, 0, (LPARAM)m_himlButtonExpand);
SendMessage(m_hWndButton, TB_SETHOTIMAGELIST, 0, (LPARAM)m_himlButtonExpand);
}
else if (AIRSTATE_INIT == m_airState || AIRSTATE_WAITINGTORESIZE == m_airState)
{
goto Cleanup;
}
// do some calc to get window size and position...
dw = (DWORD)SendMessage(m_hWndButton, TB_GETBUTTONSIZE, 0, 0);
sz.cx = LOWORD(dw);
sz.cy = HIWORD(dw);
rc.left = rc.top = 0;
rc.right = sz.cx;
rc.bottom = sz.cy;
AdjustWindowRectEx(&rc, GetWindowLong(m_hWndButtonCont, GWL_STYLE), FALSE, GetWindowLong(m_hWndButtonCont, GWL_EXSTYLE));
// that should be all...
SetWindowPos(m_hWndButtonCont, NULL,
lRight -(rc.right-rc.left)-dwOffset, // left
lBottom-(rc.bottom-rc.top)-dwOffset, // right
rc.right -rc.left, // width
rc.bottom-rc.top, // height
SWP_NOZORDER | SWP_SHOWWINDOW); // show it
m_airButtonState = AIRBUTTONSTATE_VISIBLE;
hr = S_OK;
Cleanup:
ATOMICRELEASE(pRect);
TraceMsg(TF_AIRESIZE, "-CAutoImageResize::ShowButton, this=%p, m_airButtonState=%d", this, m_airButtonState);
return hr;
}
HRESULT CAutoImageResize::HideButton()
{
HRESULT hr = S_OK;
if (m_hWndButton)
{
ShowWindow(m_hWndButtonCont, SW_HIDE);
m_airButtonState=AIRBUTTONSTATE_HIDDEN;
}
else
hr = E_FAIL;
return hr;
}
HRESULT CAutoImageResize::DestroyButton()
{
HRESULT hr = S_OK;
TraceMsg(TF_AIRESIZE, "+CAutoImageResize::DestroyHover, this=%p, m_airButtonState=%d", this, m_airButtonState);
if (m_hWndButton)
{
// first destroy the toolbar
if (!DestroyWindow(m_hWndButton))
{
TraceMsg(TF_AIRESIZE, "In CAutoImageResize::DestroyHover, DestroyWindow(m_hWndButton) failed");
hr = E_FAIL;
}
m_hWndButton=NULL;
}
// If we have a container window...
if (m_hWndButtonCont)
{
if (m_wndProcOld)
{
// Unsubclass the window
SetWindowLongPtr(m_hWndButtonCont, GWLP_WNDPROC, (LONG_PTR)m_wndProcOld);
m_wndProcOld = NULL;
}
// Clear the window word
SetWindowPtr(m_hWndButtonCont, GWLP_USERDATA, NULL);
// then destroy the rebar
if (!DestroyWindow(m_hWndButtonCont))
{
hr = E_FAIL;
goto Cleanup;
}
m_hWndButtonCont = NULL;
}
// and destroy the image lists...
if (m_himlButtonShrink)
{
ImageList_Destroy(m_himlButtonShrink);
m_himlButtonShrink = NULL;
}
if (m_himlButtonExpand)
{
ImageList_Destroy(m_himlButtonExpand);
m_himlButtonExpand = NULL;
}
Cleanup:
TraceMsg(TF_AIRESIZE, "-CAutoImageResize::DestroyHover, this=%p, hr=%x", this, hr);
return hr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Event Handlers:
HRESULT CAutoImageResize::HandleMouseover()
{
HRESULT hr = S_OK;
if (AIRBUTTONSTATE_NOBUTTON == m_airButtonState)
{
return S_OK;
}
if (!m_hWndButton)
{
hr = CreateButton();
}
if (m_hWndButton)
{
m_airButtonState = AIRBUTTONSTATE_WAITINGTOSHOW;
SetTimer(m_hWndButton, IDT_AIR_TIMER, AIR_TIMER, s_TimerProc);
}
return hr;
}
HRESULT CAutoImageResize::HandleMouseout()
{
switch(m_airButtonState)
{
case AIRBUTTONSTATE_HIDDEN:
break;
case AIRBUTTONSTATE_VISIBLE:
HideButton();
break;
case AIRBUTTONSTATE_WAITINGTOSHOW:
m_airButtonState=AIRBUTTONSTATE_HIDDEN;
KillTimer(m_hWndButton, IDT_AIR_TIMER);
break;
}
return S_OK;
}
HRESULT CAutoImageResize::HandleScroll()
{
RECT rect;
if (AIRBUTTONSTATE_VISIBLE == m_airButtonState)
{
ASSERT(m_hWndButtonCont);
ASSERT(m_pEle2);
GetWindowRect(m_hWndButtonCont, &rect);
HideButton();
ShowButton();
rect.top -= 3*AIR_MIN_CY;
rect.bottom += 2*AIR_MIN_CY;
rect.left -= 3*AIR_MIN_CX;
rect.right += 2*AIR_MIN_CX;
// redraw the button
RedrawWindow(m_hWnd, &rect, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
}
return S_OK;
}
HRESULT CAutoImageResize::HandleResize()
{
// if the image previously fit in the window, but the user resized the window and now
// we have resized the image, we should reset the button state so the user actually gets
// a button...
if (AIRBUTTONSTATE_NOBUTTON == m_airButtonState)
{
m_airButtonState = AIRBUTTONSTATE_HIDDEN;
}
// if the users has decided they want the image expanded by clicking the button to expand it,
// we should honor that and not resize the image simply because the window changes size
if (AIRSTATE_NORMAL == m_airUsersLastChoice)
{
return S_OK;
}
m_bWindowResizing = TRUE;
DoAutoImageResize();
m_bWindowResizing = FALSE;
return S_OK;
}
HRESULT CAutoImageResize::HandleBeforePrint()
{
m_airBeforePrintState = m_airState;
if (AIRSTATE_RESIZED == m_airState)
{
DoAutoImageResize();
}
return S_OK;
}
HRESULT CAutoImageResize::HandleAfterPrint()
{
if (AIRSTATE_RESIZED == m_airBeforePrintState &&
AIRSTATE_NORMAL == m_airState)
{
DoAutoImageResize();
}
return S_OK;
}
HRESULT CAutoImageResize::HandleEvent(IHTMLElement *pEle, EVENTS Event, IHTMLEventObj *pEventObj)
{
TraceMsg(TF_AIRESIZE, "CAutoImageResize::HandleEvent Event=%ws", EventsToSink[Event].pwszEventName);
HRESULT hr = S_OK;
m_eventsCurr = Event;
switch(Event)
{
case EVENT_SCROLL:
HandleScroll();
break;
case EVENT_MOUSEOVER:
hr = HandleMouseover();
break;
case EVENT_MOUSEOUT:
hr = HandleMouseout();
break;
case EVENT_RESIZE:
hr = HandleResize();
break;
case EVENT_BEFOREPRINT:
hr = HandleBeforePrint();
break;
case EVENT_AFTERPRINT:
hr = HandleAfterPrint();
break;
default:
//do nothing?
break;
}
return (hr);
}
////////////////////////////////////////////////////////////////////////////////////////////////
// this is stolen from iforms.cpp:
//=========================================================================
//
// Event sinking class
//
// We simply implement IDispatch and make a call into our parent when
// we receive a sinked event.
//
//=========================================================================
CAutoImageResize::CEventSink::CEventSink(CAutoImageResizeEventSinkCallback *pParent)
{
TraceMsg(TF_AIRESIZE, "CAutoImageResize::CEventSink::CEventSink");
DllAddRef();
m_cRef = 1;
m_pParent = pParent;
}
CAutoImageResize::CEventSink::~CEventSink()
{
TraceMsg(TF_AIRESIZE, "CAutoImageResize::CEventSink::~CEventSink");
ASSERT( m_cRef == 0 );
DllRelease();
}
STDMETHODIMP CAutoImageResize::CEventSink::QueryInterface(REFIID riid, void **ppv)
{
*ppv = NULL;
if ((IID_IDispatch == riid) ||
(IID_IUnknown == riid))
{
*ppv = (IDispatch *)this;
}
if (NULL != *ppv)
{
((IUnknown *)*ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CAutoImageResize::CEventSink::AddRef(void)
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CAutoImageResize::CEventSink::Release(void)
{
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
HRESULT CAutoImageResize::CEventSink::SinkEvents(IHTMLElement2 *pEle2, int iNum, EVENTS *pEvents)
{
VARIANT_BOOL bSuccess = VARIANT_TRUE;
for (int i=0; i<iNum; i++)
{
BSTR bstrEvent = SysAllocString(CAutoImageResizeEventSinkCallback::EventsToSink[(int)(pEvents[i])].pwszEventSubscribe);
if (bstrEvent)
{
pEle2->attachEvent(bstrEvent, (IDispatch *)this, &bSuccess);
SysFreeString(bstrEvent);
}
else
{
bSuccess = VARIANT_FALSE;
}
if (!bSuccess)
break;
}
return (bSuccess) ? S_OK : E_FAIL;
}
HRESULT CAutoImageResize::CEventSink::SinkEvents(IHTMLWindow3 *pWin3, int iNum, EVENTS *pEvents)
{
VARIANT_BOOL bSuccess = VARIANT_TRUE;
for (int i=0; i<iNum; i++)
{
BSTR bstrEvent = SysAllocString(CAutoImageResizeEventSinkCallback::EventsToSink[(int)(pEvents[i])].pwszEventSubscribe);
if (bstrEvent)
{
pWin3->attachEvent(bstrEvent, (IDispatch *)this, &bSuccess);
SysFreeString(bstrEvent);
}
else
{
bSuccess = VARIANT_FALSE;
}
if (!bSuccess)
break;
}
return (bSuccess) ? S_OK : E_FAIL;
}
HRESULT CAutoImageResize::CEventSink::UnSinkEvents(IHTMLElement2 *pEle2, int iNum, EVENTS *pEvents)
{
for (int i=0; i<iNum; i++)
{
BSTR bstrEvent = SysAllocString(CAutoImageResizeEventSinkCallback::EventsToSink[(int)(pEvents[i])].pwszEventSubscribe);
if (bstrEvent)
{
pEle2->detachEvent(bstrEvent, (IDispatch *)this);
SysFreeString(bstrEvent);
}
}
return S_OK;
}
HRESULT CAutoImageResize::CEventSink::UnSinkEvents(IHTMLWindow3 *pWin3, int iNum, EVENTS *pEvents)
{
for (int i=0; i<iNum; i++)
{
BSTR bstrEvent = SysAllocString(CAutoImageResizeEventSinkCallback::EventsToSink[(int)(pEvents[i])].pwszEventSubscribe);
if (bstrEvent)
{
pWin3->detachEvent(bstrEvent, (IDispatch *)this);
SysFreeString(bstrEvent);
}
}
return S_OK;
}
// IDispatch
STDMETHODIMP CAutoImageResize::CEventSink::GetTypeInfoCount(UINT* /*pctinfo*/)
{
return E_NOTIMPL;
}
STDMETHODIMP CAutoImageResize::CEventSink::GetTypeInfo(/* [in] */ UINT /*iTInfo*/,
/* [in] */ LCID /*lcid*/,
/* [out] */ ITypeInfo** /*ppTInfo*/)
{
return E_NOTIMPL;
}
STDMETHODIMP CAutoImageResize::CEventSink::GetIDsOfNames(
REFIID riid,
OLECHAR** rgszNames,
UINT cNames,
LCID lcid,
DISPID* rgDispId)
{
return E_NOTIMPL;
}
STDMETHODIMP CAutoImageResize::CEventSink::Invoke(
DISPID dispIdMember,
REFIID, LCID,
WORD wFlags,
DISPPARAMS* pDispParams,
VARIANT* pVarResult,
EXCEPINFO*,
UINT* puArgErr)
{
if (m_pParent && pDispParams && pDispParams->cArgs>=1)
{
if (pDispParams->rgvarg[0].vt == VT_DISPATCH)
{
IHTMLEventObj *pObj=NULL;
if (SUCCEEDED(pDispParams->rgvarg[0].pdispVal->QueryInterface(IID_IHTMLEventObj, (void **)&pObj) && pObj))
{
EVENTS Event=EVENT_BOGUS;
BSTR bstrEvent=NULL;
pObj->get_type(&bstrEvent);
if (bstrEvent)
{
for (int i=0; i<ARRAYSIZE(CAutoImageResizeEventSinkCallback::EventsToSink); i++)
{
if (!StrCmpCW(bstrEvent, CAutoImageResizeEventSinkCallback::EventsToSink[i].pwszEventName))
{
Event = (EVENTS) i;
break;
}
}
SysFreeString(bstrEvent);
}
if (Event != EVENT_BOGUS)
{
IHTMLElement *pEle=NULL;
pObj->get_srcElement(&pEle);
// EVENT_SCROLL comes from our window so we won't have an
// element for it
if (pEle || (Event == EVENT_SCROLL) || (Event == EVENT_RESIZE) || (Event == EVENT_BEFOREPRINT) || (Event == EVENT_AFTERPRINT))
{
// Call the event handler here
m_pParent->HandleEvent(pEle, Event, pObj);
if (pEle)
{
pEle->Release();
}
}
}
pObj->Release();
}
}
}
return S_OK;
}
#undef TF_AIRESIZE