#include "priv.h" #include #include #include "hlframe.h" #include "shldisp.h" #include "opsprof.h" #include "resource.h" #include #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; iattachEvent(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; iattachEvent(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; idetachEvent(bstrEvent, (IDispatch *)this); SysFreeString(bstrEvent); } } return S_OK; } HRESULT CAutoImageResize::CEventSink::UnSinkEvents(IHTMLWindow3 *pWin3, int iNum, EVENTS *pEvents) { for (int i=0; idetachEvent(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; iget_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