Source code of Windows XP (NT5)
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.

1312 lines
35 KiB

  1. #include "priv.h"
  2. #include <iehelpid.h>
  3. #include <pstore.h>
  4. #include "hlframe.h"
  5. #include "shldisp.h"
  6. #include "opsprof.h"
  7. #include "resource.h"
  8. #include <mluisupp.h>
  9. #include "htmlstr.h"
  10. #include "airesize.h"
  11. #include "mshtmcid.h"
  12. #include "util.h"
  13. #include "winuser.h"
  14. //////////////////////////////////////////////////////////////////////////////////
  15. //
  16. // filename: airesize.cpp
  17. //
  18. // description: implements the autoimageresize feature
  19. //
  20. // notes:
  21. //
  22. // history: 03.07.2001 by jeffdav
  23. //
  24. //////////////////////////////////////////////////////////////////////////////////
  25. extern HINSTANCE g_hinst;
  26. #define TF_AIRESIZE TF_CUSTOM2
  27. CAutoImageResizeEventSinkCallback::EventSinkEntry CAutoImageResizeEventSinkCallback::EventsToSink[] =
  28. {
  29. { EVENT_MOUSEOVER, L"onmouseover", L"mouseover" },
  30. { EVENT_MOUSEOUT, L"onmouseout", L"mouseout" },
  31. { EVENT_SCROLL, L"onscroll", L"scroll" },
  32. { EVENT_RESIZE, L"onresize", L"resize" },
  33. { EVENT_BEFOREPRINT, L"onbeforeprint", L"beforeprint"},
  34. { EVENT_AFTERPRINT, L"onafterprint", L"afterprint" }
  35. };
  36. // autoimage resize states
  37. enum
  38. {
  39. AIRSTATE_BOGUS = 0,
  40. AIRSTATE_INIT,
  41. AIRSTATE_NORMAL,
  42. AIRSTATE_RESIZED,
  43. AIRSTATE_WAITINGTORESIZE
  44. };
  45. // button states
  46. enum
  47. {
  48. AIRBUTTONSTATE_BOGUS = 0,
  49. AIRBUTTONSTATE_HIDDEN,
  50. AIRBUTTONSTATE_VISIBLE,
  51. AIRBUTTONSTATE_WAITINGTOSHOW,
  52. AIRBUTTONSTATE_NOBUTTON
  53. };
  54. ////////////////////////////////////////////////////////////////////////////
  55. // QI, AddRef, Release:
  56. STDMETHODIMP CAutoImageResize::QueryInterface(REFIID riid, void **ppv)
  57. {
  58. *ppv = NULL;
  59. if ((IID_IPropertyNotifySink == riid) || (IID_IUnknown == riid))
  60. {
  61. *ppv = (IPropertyNotifySink *)this;
  62. }
  63. if (*ppv)
  64. {
  65. ((IUnknown *)*ppv)->AddRef();
  66. return S_OK;
  67. }
  68. return E_NOINTERFACE;
  69. }
  70. STDMETHODIMP_(ULONG) CAutoImageResize::AddRef(void)
  71. {
  72. return ++m_cRef;
  73. }
  74. STDMETHODIMP_(ULONG) CAutoImageResize::Release(void)
  75. {
  76. if (--m_cRef == 0)
  77. {
  78. delete this;
  79. return 0;
  80. }
  81. return m_cRef;
  82. }
  83. //////////////////////////////////////////////////////////////////////////////
  84. // Constructor, Destructor, Init, UnInit:
  85. // constructor
  86. CAutoImageResize::CAutoImageResize()
  87. {
  88. TraceMsg(TF_AIRESIZE, "+CAutoImageResize::CAutoImageResize");
  89. m_airState = AIRSTATE_INIT;
  90. m_airUsersLastChoice= AIRSTATE_BOGUS; // we don't care until the user clicks the button
  91. m_hWndButton = NULL;
  92. m_hWnd = NULL;
  93. m_wndProcOld = NULL;
  94. m_pDoc2 = NULL;
  95. m_pEle2 = NULL;
  96. m_pWin3 = NULL;
  97. m_bWindowResizing = FALSE;
  98. m_himlButtonShrink = NULL;
  99. m_himlButtonExpand = NULL;
  100. TraceMsg(TF_AIRESIZE, "-CAutoImageResize::CAutoImageResize");
  101. }
  102. // destructor
  103. CAutoImageResize::~CAutoImageResize()
  104. {
  105. TraceMsg(TF_AIRESIZE, "+CAutoImageResize::~CAutoImageResize");
  106. DestroyButton();
  107. ATOMICRELEASE(m_pEle2);
  108. ATOMICRELEASE(m_pDoc2);
  109. TraceMsg(TF_AIRESIZE, "-CAutoImageResize::~CAutoImageResize");
  110. }
  111. HRESULT CAutoImageResize::Init(IHTMLDocument2 *pDoc2)
  112. {
  113. HRESULT hr = S_OK;
  114. TraceMsg(TF_AIRESIZE, "+CAutoImageResize::Init");
  115. ASSERT(pDoc2);
  116. //sink things
  117. IHTMLElement2 *pEle2 = NULL;
  118. IHTMLElementCollection *pCollect = NULL;
  119. IHTMLElementCollection *pSubCollect = NULL;
  120. IDispatch *pDisp = NULL;
  121. VARIANT TagName;
  122. ULONG ulCount = 0;
  123. VARIANTARG va1;
  124. VARIANTARG va2;
  125. IHTMLWindow3 *pWin3 = NULL;
  126. IOleWindow *pOleWin = NULL;
  127. // ...remember this...
  128. m_pDoc2 = pDoc2;
  129. pDoc2->AddRef();
  130. // ...remember the hwnd also...
  131. hr = m_pDoc2->QueryInterface(IID_IOleWindow,(void **)&pOleWin);
  132. if (FAILED(hr))
  133. goto Cleanup;
  134. pOleWin->GetWindow(&m_hWnd);
  135. // setup variant for finding all the IMG tags...
  136. TagName.vt = VT_BSTR;
  137. TagName.bstrVal = (BSTR)c_bstr_IMG;
  138. //get all tags
  139. hr = pDoc2->get_all(&pCollect);
  140. if (FAILED(hr))
  141. goto Cleanup;
  142. //get all IMG tags
  143. hr = pCollect->tags(TagName, &pDisp);
  144. if (FAILED(hr))
  145. goto Cleanup;
  146. if (pDisp)
  147. {
  148. hr = pDisp->QueryInterface(IID_IHTMLElementCollection,(void **)&pSubCollect);
  149. ATOMICRELEASE(pDisp);
  150. }
  151. if (FAILED(hr))
  152. goto Cleanup;
  153. //get IMG tag count
  154. hr = pSubCollect->get_length((LONG *)&ulCount);
  155. if (FAILED(hr))
  156. goto Cleanup;
  157. // highlander theorem: there can be only one!
  158. // bt's corollary: there must be exactally one.
  159. if (1 != ulCount)
  160. goto Cleanup;
  161. va1.vt = VT_I4;
  162. va2.vt = VT_EMPTY;
  163. pDisp = NULL;
  164. va1.lVal = (LONG)0;
  165. pSubCollect->item(va1, va2, &pDisp);
  166. // create event sink for the image
  167. if (!m_pSink && pDisp)
  168. m_pSink = new CEventSink(this);
  169. if (pDisp)
  170. {
  171. hr = pDisp->QueryInterface(IID_IHTMLElement2, (void **)&pEle2);
  172. if (FAILED(hr))
  173. goto Cleanup;
  174. ASSERT(m_pSink);
  175. if (m_pSink && pEle2)
  176. {
  177. EVENTS events[] = { EVENT_MOUSEOVER, EVENT_MOUSEOUT };
  178. m_pSink->SinkEvents(pEle2, ARRAYSIZE(events), events);
  179. m_pEle2=pEle2;
  180. pEle2->AddRef();
  181. }
  182. ATOMICRELEASE(pEle2);
  183. ATOMICRELEASE(pDisp);
  184. }
  185. // sink scroll event from the window, because it doesn't come from elements.
  186. if (m_pSink)
  187. {
  188. Win3FromDoc2(m_pDoc2, &pWin3);
  189. if (pWin3)
  190. {
  191. m_pWin3 = pWin3;
  192. m_pWin3->AddRef();
  193. EVENTS events[] = { EVENT_SCROLL, EVENT_RESIZE, EVENT_BEFOREPRINT, EVENT_AFTERPRINT };
  194. m_pSink->SinkEvents(pWin3, ARRAYSIZE(events), events);
  195. }
  196. }
  197. // end sinking things
  198. // Init() gets called when onload fires, so the image *should* be ready
  199. // to get adjusted, if need be...
  200. DoAutoImageResize();
  201. Cleanup:
  202. ATOMICRELEASE(pCollect);
  203. ATOMICRELEASE(pSubCollect);
  204. ATOMICRELEASE(pWin3);
  205. ATOMICRELEASE(pDisp);
  206. ATOMICRELEASE(pEle2);
  207. ATOMICRELEASE(pOleWin);
  208. TraceMsg(TF_AIRESIZE, "-CAutoImageResize::Init");
  209. return hr;
  210. }
  211. HRESULT CAutoImageResize::UnInit()
  212. {
  213. // Unhook regular event sink
  214. TraceMsg(TF_AIRESIZE, "+CAutoImageResize::UnInit");
  215. DestroyButton();
  216. if (m_pSink)
  217. {
  218. if (m_pWin3)
  219. {
  220. EVENTS events[] = { EVENT_SCROLL, EVENT_RESIZE, EVENT_BEFOREPRINT, EVENT_AFTERPRINT };
  221. m_pSink->UnSinkEvents(m_pWin3, ARRAYSIZE(events), events);
  222. SAFERELEASE(m_pWin3);
  223. }
  224. m_pSink->SetParent(NULL);
  225. ATOMICRELEASE(m_pSink);
  226. }
  227. SAFERELEASE(m_pEle2);
  228. SAFERELEASE(m_pDoc2);
  229. TraceMsg(TF_AIRESIZE, "-CAutoImageResize::UnInit");
  230. return S_OK;
  231. }
  232. ////////////////////////////////////////////////////////////////////////////////
  233. // AutoImageResize Functions:
  234. HRESULT CAutoImageResize::DoAutoImageResize()
  235. {
  236. HRESULT hr = S_OK;
  237. IHTMLImgElement *pImgEle = NULL;
  238. LONG lHeight = 0;
  239. LONG lWidth = 0;
  240. LONG lNewHeight = 0;
  241. LONG lNewWidth = 0;
  242. LONG lScrHt = 0;
  243. LONG lScrWd = 0;
  244. RECT rcBrowserWnd;
  245. ASSERT(m_pEle2);
  246. // get an IHTMLImgElement from the IHTMLElement cached...
  247. hr = m_pEle2->QueryInterface(IID_IHTMLImgElement, (void **)&pImgEle);
  248. if (FAILED(hr) || !pImgEle)
  249. goto Cleanup;
  250. // get the current dimensions
  251. if (FAILED(pImgEle->get_height(&lHeight)) || FAILED(pImgEle->get_width(&lWidth)))
  252. goto Cleanup;
  253. // if this is the first time through, we need to take care of some init stuff
  254. if (AIRSTATE_INIT == m_airState)
  255. {
  256. // cache orig dimensions
  257. m_airOrigSize.x = lWidth;
  258. m_airOrigSize.y = lHeight;
  259. // INIT done, promote to NORMAL
  260. m_airState = AIRSTATE_NORMAL;
  261. }
  262. // check to see if we are being called because the user is resizing the window
  263. // and then massage the state as necessary.
  264. if (m_bWindowResizing)
  265. {
  266. m_airState = AIRSTATE_NORMAL;
  267. }
  268. switch (m_airState)
  269. {
  270. case AIRSTATE_NORMAL:
  271. // how big is the window?
  272. if (GetClientRect(m_hWnd, &rcBrowserWnd))
  273. {
  274. lScrHt = rcBrowserWnd.bottom - rcBrowserWnd.top;
  275. lScrWd = rcBrowserWnd.right - rcBrowserWnd.left;
  276. // is the image bigger then the window?
  277. if (lScrWd < lWidth)
  278. m_airState=AIRSTATE_WAITINGTORESIZE;
  279. if (lScrHt < lHeight)
  280. m_airState=AIRSTATE_WAITINGTORESIZE;
  281. }
  282. else
  283. goto Cleanup;
  284. // if the window is resizing, we may need to expand the image, so massage the state again...
  285. // (there is a check later on to make sure we don't expand too far...)
  286. if (m_bWindowResizing)
  287. {
  288. m_airState = AIRSTATE_WAITINGTORESIZE;
  289. }
  290. // image didn't fit, so we must resize now
  291. if (AIRSTATE_WAITINGTORESIZE == m_airState)
  292. {
  293. // calculate new size:
  294. if (MulDiv(lWidth,1000,lScrWd) < MulDiv(lHeight,1000,lScrHt))
  295. {
  296. lNewHeight = lScrHt-AIR_SCREEN_CONSTANTY;
  297. lNewWidth = MulDiv(lNewHeight,m_airOrigSize.x,m_airOrigSize.y);
  298. }
  299. else
  300. {
  301. lNewWidth = lScrWd-AIR_SCREEN_CONSTANTX;
  302. lNewHeight = MulDiv(lNewWidth, m_airOrigSize.y, m_airOrigSize.x);
  303. }
  304. // we don't ever want to resize to be LARGER then the original...
  305. if ((lNewHeight > m_airOrigSize.y) || (lNewWidth > m_airOrigSize.x))
  306. {
  307. if (m_bWindowResizing)
  308. {
  309. // restore orig size cause it should fit and turn off the button
  310. lNewHeight = m_airOrigSize.y;
  311. lNewWidth = m_airOrigSize.x;
  312. m_airButtonState = AIRBUTTONSTATE_NOBUTTON;
  313. }
  314. else
  315. goto Cleanup;
  316. }
  317. if (FAILED(pImgEle->put_height(lNewHeight)) || FAILED(pImgEle->put_width(lNewWidth)))
  318. {
  319. goto Cleanup;
  320. }
  321. else
  322. {
  323. m_airState=AIRSTATE_RESIZED;
  324. if (AIRBUTTONSTATE_VISIBLE == m_airButtonState)
  325. {
  326. // reposition button
  327. HideButton();
  328. ShowButton();
  329. }
  330. }
  331. }
  332. else
  333. {
  334. // It fit in the browser window so we don't need to do any work yet...
  335. // If they resize the window or something we need to check again...
  336. m_airButtonState=AIRBUTTONSTATE_NOBUTTON;
  337. }
  338. break;
  339. case AIRSTATE_RESIZED:
  340. // restore the image to its normal size
  341. if (FAILED(pImgEle->put_height(m_airOrigSize.y)) ||
  342. FAILED(pImgEle->put_width (m_airOrigSize.x)))
  343. {
  344. goto Cleanup;
  345. }
  346. else
  347. {
  348. m_airState=AIRSTATE_NORMAL;
  349. if (AIRBUTTONSTATE_VISIBLE == m_airButtonState)
  350. {
  351. // reposition button
  352. HideButton();
  353. ShowButton();
  354. }
  355. }
  356. break;
  357. case AIRSTATE_WAITINGTORESIZE:
  358. // we should never be in this state at this time!
  359. ASSERT(m_airState!=AIRSTATE_WAITINGTORESIZE);
  360. break;
  361. default:
  362. break;
  363. }
  364. Cleanup:
  365. ATOMICRELEASE(pImgEle);
  366. return hr;
  367. }
  368. /////////////////////////////////////////////////////////////////////////////////////////////////
  369. // Timer Proc:
  370. LRESULT CALLBACK CAutoImageResize::s_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  371. {
  372. CAutoImageResize* pThis = (CAutoImageResize*)GetWindowPtr(hWnd, GWLP_USERDATA);
  373. TraceMsg(TF_AIRESIZE, "+CAutoImageResize::s_WndProc hWnd=%x, pThis=%p", hWnd, pThis);
  374. HRESULT hr = S_OK;
  375. IOleCommandTarget *pOleCommandTarget = NULL;
  376. UINT iToolTip = NULL;
  377. switch (uMsg)
  378. {
  379. case WM_SIZE:
  380. if (!pThis)
  381. break;
  382. SetWindowPos(pThis->m_hWndButton, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOZORDER | SWP_NOACTIVATE);
  383. break;
  384. case WM_ERASEBKGND:
  385. if (!pThis)
  386. break;
  387. {
  388. RECT rc;
  389. HBRUSH hb = GetSysColorBrush(COLOR_3DFACE);
  390. GetClientRect(pThis->m_hWndButton, &rc);
  391. FillRect((HDC)wParam, &rc, hb);
  392. return TRUE;
  393. }
  394. case WM_COMMAND:
  395. if (!pThis)
  396. break;
  397. switch(LOWORD(wParam))
  398. {
  399. case IDM_AIR_BUTTON:
  400. if (AIRSTATE_NORMAL == pThis->m_airState)
  401. {
  402. pThis->m_airUsersLastChoice = AIRSTATE_RESIZED;
  403. }
  404. else if (AIRSTATE_RESIZED == pThis->m_airState)
  405. {
  406. pThis->m_airUsersLastChoice = AIRSTATE_NORMAL;
  407. }
  408. pThis->DoAutoImageResize();
  409. break;
  410. }
  411. break;
  412. case WM_NOTIFY: // tooltips...
  413. if (!pThis)
  414. break;
  415. switch (((LPNMHDR)lParam)->code)
  416. {
  417. case TTN_NEEDTEXT:
  418. {
  419. if (AIRSTATE_NORMAL == pThis->m_airState)
  420. {
  421. iToolTip = IDS_AIR_SHRINK;
  422. }
  423. else if (AIRSTATE_RESIZED == pThis->m_airState)
  424. {
  425. iToolTip = IDS_AIR_EXPAND;
  426. }
  427. LPTOOLTIPTEXT lpToolTipText;
  428. TCHAR szBuf[MAX_PATH];
  429. lpToolTipText = (LPTOOLTIPTEXT)lParam;
  430. hr = MLLoadString(iToolTip,
  431. szBuf,
  432. ARRAYSIZE(szBuf));
  433. lpToolTipText->lpszText = szBuf;
  434. break;
  435. }
  436. }
  437. break;
  438. case WM_SETTINGCHANGE:
  439. {
  440. pThis->DestroyButton(); // to stop wierd window distortion
  441. break;
  442. }
  443. case WM_CONTEXTMENU:
  444. {
  445. // should we be consistant and have a turn-me-off/help context menu?
  446. }
  447. break;
  448. default:
  449. return(DefWindowProc(hWnd, uMsg, wParam, lParam));
  450. }
  451. TraceMsg(TF_AIRESIZE, "-CAutoImageResize::s_WndProc hWnd=%x, pThis=%p", hWnd, pThis);
  452. return (hr);
  453. }
  454. /////////////////////////////////////////////////////////////////////////////////////////////////
  455. // Timer Proc:
  456. VOID CALLBACK CAutoImageResize::s_TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
  457. {
  458. TraceMsg(TF_AIRESIZE, "+CAutoImageResize::TimerProc");
  459. CAutoImageResize* pThis = (CAutoImageResize*)GetWindowPtr(hwnd, GWLP_USERDATA);
  460. switch (uMsg)
  461. {
  462. case WM_TIMER:
  463. KillTimer(hwnd, IDT_AIR_TIMER);
  464. if (pThis && (AIRBUTTONSTATE_WAITINGTOSHOW == pThis->m_airButtonState))
  465. {
  466. // Our hover bar is waiting to be shown.
  467. if (pThis->m_pEle2)
  468. {
  469. // We still have an element. Show it.
  470. pThis->m_airButtonState = AIRBUTTONSTATE_VISIBLE;
  471. pThis->ShowButton();
  472. }
  473. else
  474. {
  475. // Our timer popped, but we don't have an element.
  476. pThis->HideButton();
  477. }
  478. }
  479. break;
  480. default:
  481. break;
  482. }
  483. TraceMsg(TF_AIRESIZE, "-CAutoImageResize::TimerProc");
  484. }
  485. /////////////////////////////////////////////////////////////////////////////////////////////////
  486. // Button Functions:
  487. HRESULT CAutoImageResize::CreateButton()
  488. {
  489. HRESULT hr = S_OK;
  490. SIZE size = {0,0};
  491. TraceMsg(TF_AIRESIZE, "+CAutoImageResize::CreateHover, this=%p, m_airButtonState=%d", this, m_airButtonState);
  492. InitCommonControls();
  493. WNDCLASS wc = {0};
  494. wc.style = CS_HREDRAW | CS_VREDRAW;
  495. wc.lpszClassName = TEXT("AutoImageResizeHost");
  496. wc.lpfnWndProc = s_WndProc;
  497. wc.hInstance = g_hinst;
  498. wc.hbrBackground = HBRUSH(COLOR_BTNFACE);
  499. RegisterClass(&wc);
  500. if (!m_hWndButtonCont)
  501. {
  502. m_hWndButtonCont = CreateWindow(TEXT("AutoImageResizeHost"), TEXT(""), WS_DLGFRAME | WS_VISIBLE | WS_CHILD /*| WS_POPUP*/,
  503. 0, 0, 0, 0, m_hWnd, NULL, g_hinst, NULL);
  504. if (!m_hWndButtonCont)
  505. {
  506. TraceMsg(TF_AIRESIZE | TF_WARNING, "CAutoImageResize::CreateButton, unable to create m_hWndButtonCont");
  507. hr = E_FAIL;
  508. goto Cleanup;
  509. }
  510. // setup the window callback stuff...
  511. ASSERT(m_wndProcOld == NULL);
  512. m_wndProcOld = (WNDPROC)SetWindowLongPtr(m_hWndButtonCont, GWLP_WNDPROC, (LONG_PTR)s_WndProc);
  513. // pass in the this pointer so the button can call member functions
  514. ASSERT(GetWindowPtr(m_hWndButtonCont, GWLP_USERDATA) == NULL);
  515. SetWindowPtr(m_hWndButtonCont, GWLP_USERDATA, this);
  516. }
  517. // create the button
  518. if (!m_hWndButton)
  519. {
  520. m_hWndButton = CreateWindow(TOOLBARCLASSNAME, TEXT(""), TBSTYLE_TOOLTIPS | CCS_NODIVIDER | TBSTYLE_FLAT | WS_VISIBLE | WS_CHILD,
  521. 0,0,0,0, m_hWndButtonCont, NULL, g_hinst, NULL);
  522. if (!m_hWndButton)
  523. {
  524. TraceMsg(TF_AIRESIZE | TF_WARNING, "CAutoImageResize::CreateButton, unable to create m_hWndButton");
  525. hr = E_FAIL;
  526. goto Cleanup;
  527. }
  528. ASSERT(GetWindowPtr(m_hWndButton, GWLP_USERDATA) == NULL);
  529. SetWindowPtr(m_hWndButton, GWLP_USERDATA, this);
  530. // set cc version for this too, and the sizeof tbbutton struct...
  531. SendMessage(m_hWndButton, CCM_SETVERSION, COMCTL32_VERSION, 0);
  532. SendMessage(m_hWndButton, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
  533. }
  534. if (!m_himlButtonExpand)
  535. {
  536. m_himlButtonExpand = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_AIR_EXPAND), 32, 0, CLR_DEFAULT, IMAGE_BITMAP, LR_CREATEDIBSECTION);
  537. if (!m_himlButtonExpand)
  538. {
  539. TraceMsg(TF_AIRESIZE | TF_WARNING, "CAutoImageResize::CreateButton, unable to create m_himlButtonExpand");
  540. hr = E_FAIL;
  541. goto Cleanup;
  542. }
  543. }
  544. if (!m_himlButtonShrink)
  545. {
  546. m_himlButtonShrink = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_AIR_SHRINK), 32, 0, CLR_DEFAULT, IMAGE_BITMAP, LR_CREATEDIBSECTION);
  547. if (!m_himlButtonShrink)
  548. {
  549. TraceMsg(TF_AIRESIZE | TF_WARNING, "CAutoImageResize::CreateButton, unable to create m_himlButtonShrink");
  550. hr = E_FAIL;
  551. goto Cleanup;
  552. }
  553. }
  554. // set image list and hot image list
  555. SendMessage(m_hWndButton, TB_SETIMAGELIST, 0, (LPARAM)m_himlButtonExpand);
  556. SendMessage(m_hWndButton, TB_SETHOTIMAGELIST, 0, (LPARAM)m_himlButtonExpand);
  557. // add the buttons
  558. TBBUTTON tbAirButton;
  559. tbAirButton.iBitmap = 0;
  560. tbAirButton.idCommand = IDM_AIR_BUTTON;
  561. tbAirButton.fsState = TBSTATE_ENABLED;
  562. tbAirButton.fsStyle = TBSTYLE_BUTTON;
  563. tbAirButton.dwData = 0;
  564. tbAirButton.iString = 0;
  565. SendMessage(m_hWndButton, TB_INSERTBUTTON, 0, (LPARAM)&tbAirButton);
  566. Cleanup:
  567. TraceMsg(TF_AIRESIZE, "-CAutoImageResize::CreateButton, this=%p, m_airButtonState=%d", this, m_airButtonState);
  568. return hr;
  569. }
  570. HRESULT CAutoImageResize::ShowButton()
  571. {
  572. HRESULT hr = E_FAIL;
  573. IHTMLRect *pRect = NULL;
  574. LONG lLeft = 0; // these are the screen coords
  575. LONG lRight = 0; // we get right and bottom to det size of image
  576. LONG lTop = 0;
  577. LONG lBottom = 0;
  578. DWORD dwOffset = MP_GetOffsetInfoFromRegistry();
  579. RECT rcBrowserWnd;
  580. WORD wImage = NULL;
  581. DWORD dw;
  582. SIZE sz;
  583. RECT rc;
  584. TraceMsg(TF_AIRESIZE, "+CAutoImageResize::ShowButton, this=%p, m_airButtonState=%d", this, m_airButtonState);
  585. ASSERT(m_pEle2);
  586. // get the coords of the image...
  587. if (SUCCEEDED(m_pEle2->getBoundingClientRect(&pRect)) && pRect)
  588. {
  589. pRect->get_left(&lLeft);
  590. pRect->get_right(&lRight);
  591. pRect->get_top(&lTop);
  592. pRect->get_bottom(&lBottom);
  593. }
  594. else
  595. goto Cleanup;
  596. // make sure we are inside the browser window...
  597. if (GetClientRect(m_hWnd, &rcBrowserWnd))
  598. {
  599. // if the browser window is less then a certain min size, we
  600. // don't display the button...
  601. if ((rcBrowserWnd.right - rcBrowserWnd.left < AIR_MIN_BROWSER_SIZE) ||
  602. (rcBrowserWnd.bottom - rcBrowserWnd.top < AIR_MIN_BROWSER_SIZE))
  603. goto Cleanup;
  604. // if the browser window is larger then the image, we don't display
  605. // the button...
  606. if ((AIRSTATE_NORMAL == m_airState) &&
  607. (rcBrowserWnd.left < lLeft ) &&
  608. (rcBrowserWnd.right > lRight ) &&
  609. (rcBrowserWnd.top < lTop ) &&
  610. (rcBrowserWnd.bottom > lBottom))
  611. goto Cleanup;
  612. // adjust for scrollbars
  613. if (lRight > rcBrowserWnd.right - AIR_SCROLLBAR_SIZE_V)
  614. {
  615. lRight = rcBrowserWnd.right - AIR_SCROLLBAR_SIZE_V;
  616. }
  617. if (lBottom > rcBrowserWnd.bottom - AIR_SCROLLBAR_SIZE_H)
  618. {
  619. lBottom = rcBrowserWnd.bottom - AIR_SCROLLBAR_SIZE_H;
  620. }
  621. }
  622. else
  623. goto Cleanup;
  624. // someone tried to show the button, but it doesn't exist.
  625. // this is ok, if we actually have an element, so fix it for them.
  626. if (!m_hWndButtonCont && m_pEle2)
  627. CreateButton();
  628. // make sure the image list exists
  629. if (!m_himlButtonShrink || !m_himlButtonExpand)
  630. {
  631. hr = E_FAIL;
  632. goto Cleanup;
  633. }
  634. if (AIRSTATE_NORMAL == m_airState)
  635. {
  636. SendMessage(m_hWndButton, TB_SETIMAGELIST, 0, (LPARAM)m_himlButtonShrink);
  637. SendMessage(m_hWndButton, TB_SETHOTIMAGELIST, 0, (LPARAM)m_himlButtonShrink);
  638. }
  639. else if (AIRSTATE_RESIZED == m_airState)
  640. {
  641. SendMessage(m_hWndButton, TB_SETIMAGELIST, 0, (LPARAM)m_himlButtonExpand);
  642. SendMessage(m_hWndButton, TB_SETHOTIMAGELIST, 0, (LPARAM)m_himlButtonExpand);
  643. }
  644. else if (AIRSTATE_INIT == m_airState || AIRSTATE_WAITINGTORESIZE == m_airState)
  645. {
  646. goto Cleanup;
  647. }
  648. // do some calc to get window size and position...
  649. dw = (DWORD)SendMessage(m_hWndButton, TB_GETBUTTONSIZE, 0, 0);
  650. sz.cx = LOWORD(dw);
  651. sz.cy = HIWORD(dw);
  652. rc.left = rc.top = 0;
  653. rc.right = sz.cx;
  654. rc.bottom = sz.cy;
  655. AdjustWindowRectEx(&rc, GetWindowLong(m_hWndButtonCont, GWL_STYLE), FALSE, GetWindowLong(m_hWndButtonCont, GWL_EXSTYLE));
  656. // that should be all...
  657. SetWindowPos(m_hWndButtonCont, NULL,
  658. lRight -(rc.right-rc.left)-dwOffset, // left
  659. lBottom-(rc.bottom-rc.top)-dwOffset, // right
  660. rc.right -rc.left, // width
  661. rc.bottom-rc.top, // height
  662. SWP_NOZORDER | SWP_SHOWWINDOW); // show it
  663. m_airButtonState = AIRBUTTONSTATE_VISIBLE;
  664. hr = S_OK;
  665. Cleanup:
  666. ATOMICRELEASE(pRect);
  667. TraceMsg(TF_AIRESIZE, "-CAutoImageResize::ShowButton, this=%p, m_airButtonState=%d", this, m_airButtonState);
  668. return hr;
  669. }
  670. HRESULT CAutoImageResize::HideButton()
  671. {
  672. HRESULT hr = S_OK;
  673. if (m_hWndButton)
  674. {
  675. ShowWindow(m_hWndButtonCont, SW_HIDE);
  676. m_airButtonState=AIRBUTTONSTATE_HIDDEN;
  677. }
  678. else
  679. hr = E_FAIL;
  680. return hr;
  681. }
  682. HRESULT CAutoImageResize::DestroyButton()
  683. {
  684. HRESULT hr = S_OK;
  685. TraceMsg(TF_AIRESIZE, "+CAutoImageResize::DestroyHover, this=%p, m_airButtonState=%d", this, m_airButtonState);
  686. if (m_hWndButton)
  687. {
  688. // first destroy the toolbar
  689. if (!DestroyWindow(m_hWndButton))
  690. {
  691. TraceMsg(TF_AIRESIZE, "In CAutoImageResize::DestroyHover, DestroyWindow(m_hWndButton) failed");
  692. hr = E_FAIL;
  693. }
  694. m_hWndButton=NULL;
  695. }
  696. // If we have a container window...
  697. if (m_hWndButtonCont)
  698. {
  699. if (m_wndProcOld)
  700. {
  701. // Unsubclass the window
  702. SetWindowLongPtr(m_hWndButtonCont, GWLP_WNDPROC, (LONG_PTR)m_wndProcOld);
  703. m_wndProcOld = NULL;
  704. }
  705. // Clear the window word
  706. SetWindowPtr(m_hWndButtonCont, GWLP_USERDATA, NULL);
  707. // then destroy the rebar
  708. if (!DestroyWindow(m_hWndButtonCont))
  709. {
  710. hr = E_FAIL;
  711. goto Cleanup;
  712. }
  713. m_hWndButtonCont = NULL;
  714. }
  715. // and destroy the image lists...
  716. if (m_himlButtonShrink)
  717. {
  718. ImageList_Destroy(m_himlButtonShrink);
  719. m_himlButtonShrink = NULL;
  720. }
  721. if (m_himlButtonExpand)
  722. {
  723. ImageList_Destroy(m_himlButtonExpand);
  724. m_himlButtonExpand = NULL;
  725. }
  726. Cleanup:
  727. TraceMsg(TF_AIRESIZE, "-CAutoImageResize::DestroyHover, this=%p, hr=%x", this, hr);
  728. return hr;
  729. }
  730. /////////////////////////////////////////////////////////////////////////////////////////////////
  731. // Event Handlers:
  732. HRESULT CAutoImageResize::HandleMouseover()
  733. {
  734. HRESULT hr = S_OK;
  735. if (AIRBUTTONSTATE_NOBUTTON == m_airButtonState)
  736. {
  737. return S_OK;
  738. }
  739. if (!m_hWndButton)
  740. {
  741. hr = CreateButton();
  742. }
  743. if (m_hWndButton)
  744. {
  745. m_airButtonState = AIRBUTTONSTATE_WAITINGTOSHOW;
  746. SetTimer(m_hWndButton, IDT_AIR_TIMER, AIR_TIMER, s_TimerProc);
  747. }
  748. return hr;
  749. }
  750. HRESULT CAutoImageResize::HandleMouseout()
  751. {
  752. switch(m_airButtonState)
  753. {
  754. case AIRBUTTONSTATE_HIDDEN:
  755. break;
  756. case AIRBUTTONSTATE_VISIBLE:
  757. HideButton();
  758. break;
  759. case AIRBUTTONSTATE_WAITINGTOSHOW:
  760. m_airButtonState=AIRBUTTONSTATE_HIDDEN;
  761. KillTimer(m_hWndButton, IDT_AIR_TIMER);
  762. break;
  763. }
  764. return S_OK;
  765. }
  766. HRESULT CAutoImageResize::HandleScroll()
  767. {
  768. RECT rect;
  769. if (AIRBUTTONSTATE_VISIBLE == m_airButtonState)
  770. {
  771. ASSERT(m_hWndButtonCont);
  772. ASSERT(m_pEle2);
  773. GetWindowRect(m_hWndButtonCont, &rect);
  774. HideButton();
  775. ShowButton();
  776. rect.top -= 3*AIR_MIN_CY;
  777. rect.bottom += 2*AIR_MIN_CY;
  778. rect.left -= 3*AIR_MIN_CX;
  779. rect.right += 2*AIR_MIN_CX;
  780. // redraw the button
  781. RedrawWindow(m_hWnd, &rect, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
  782. }
  783. return S_OK;
  784. }
  785. HRESULT CAutoImageResize::HandleResize()
  786. {
  787. // if the image previously fit in the window, but the user resized the window and now
  788. // we have resized the image, we should reset the button state so the user actually gets
  789. // a button...
  790. if (AIRBUTTONSTATE_NOBUTTON == m_airButtonState)
  791. {
  792. m_airButtonState = AIRBUTTONSTATE_HIDDEN;
  793. }
  794. // if the users has decided they want the image expanded by clicking the button to expand it,
  795. // we should honor that and not resize the image simply because the window changes size
  796. if (AIRSTATE_NORMAL == m_airUsersLastChoice)
  797. {
  798. return S_OK;
  799. }
  800. m_bWindowResizing = TRUE;
  801. DoAutoImageResize();
  802. m_bWindowResizing = FALSE;
  803. return S_OK;
  804. }
  805. HRESULT CAutoImageResize::HandleBeforePrint()
  806. {
  807. m_airBeforePrintState = m_airState;
  808. if (AIRSTATE_RESIZED == m_airState)
  809. {
  810. DoAutoImageResize();
  811. }
  812. return S_OK;
  813. }
  814. HRESULT CAutoImageResize::HandleAfterPrint()
  815. {
  816. if (AIRSTATE_RESIZED == m_airBeforePrintState &&
  817. AIRSTATE_NORMAL == m_airState)
  818. {
  819. DoAutoImageResize();
  820. }
  821. return S_OK;
  822. }
  823. HRESULT CAutoImageResize::HandleEvent(IHTMLElement *pEle, EVENTS Event, IHTMLEventObj *pEventObj)
  824. {
  825. TraceMsg(TF_AIRESIZE, "CAutoImageResize::HandleEvent Event=%ws", EventsToSink[Event].pwszEventName);
  826. HRESULT hr = S_OK;
  827. m_eventsCurr = Event;
  828. switch(Event)
  829. {
  830. case EVENT_SCROLL:
  831. HandleScroll();
  832. break;
  833. case EVENT_MOUSEOVER:
  834. hr = HandleMouseover();
  835. break;
  836. case EVENT_MOUSEOUT:
  837. hr = HandleMouseout();
  838. break;
  839. case EVENT_RESIZE:
  840. hr = HandleResize();
  841. break;
  842. case EVENT_BEFOREPRINT:
  843. hr = HandleBeforePrint();
  844. break;
  845. case EVENT_AFTERPRINT:
  846. hr = HandleAfterPrint();
  847. break;
  848. default:
  849. //do nothing?
  850. break;
  851. }
  852. return (hr);
  853. }
  854. ////////////////////////////////////////////////////////////////////////////////////////////////
  855. // this is stolen from iforms.cpp:
  856. //=========================================================================
  857. //
  858. // Event sinking class
  859. //
  860. // We simply implement IDispatch and make a call into our parent when
  861. // we receive a sinked event.
  862. //
  863. //=========================================================================
  864. CAutoImageResize::CEventSink::CEventSink(CAutoImageResizeEventSinkCallback *pParent)
  865. {
  866. TraceMsg(TF_AIRESIZE, "CAutoImageResize::CEventSink::CEventSink");
  867. DllAddRef();
  868. m_cRef = 1;
  869. m_pParent = pParent;
  870. }
  871. CAutoImageResize::CEventSink::~CEventSink()
  872. {
  873. TraceMsg(TF_AIRESIZE, "CAutoImageResize::CEventSink::~CEventSink");
  874. ASSERT( m_cRef == 0 );
  875. DllRelease();
  876. }
  877. STDMETHODIMP CAutoImageResize::CEventSink::QueryInterface(REFIID riid, void **ppv)
  878. {
  879. *ppv = NULL;
  880. if ((IID_IDispatch == riid) ||
  881. (IID_IUnknown == riid))
  882. {
  883. *ppv = (IDispatch *)this;
  884. }
  885. if (NULL != *ppv)
  886. {
  887. ((IUnknown *)*ppv)->AddRef();
  888. return S_OK;
  889. }
  890. return E_NOINTERFACE;
  891. }
  892. STDMETHODIMP_(ULONG) CAutoImageResize::CEventSink::AddRef(void)
  893. {
  894. return ++m_cRef;
  895. }
  896. STDMETHODIMP_(ULONG) CAutoImageResize::CEventSink::Release(void)
  897. {
  898. if (--m_cRef == 0)
  899. {
  900. delete this;
  901. return 0;
  902. }
  903. return m_cRef;
  904. }
  905. HRESULT CAutoImageResize::CEventSink::SinkEvents(IHTMLElement2 *pEle2, int iNum, EVENTS *pEvents)
  906. {
  907. VARIANT_BOOL bSuccess = VARIANT_TRUE;
  908. for (int i=0; i<iNum; i++)
  909. {
  910. BSTR bstrEvent = SysAllocString(CAutoImageResizeEventSinkCallback::EventsToSink[(int)(pEvents[i])].pwszEventSubscribe);
  911. if (bstrEvent)
  912. {
  913. pEle2->attachEvent(bstrEvent, (IDispatch *)this, &bSuccess);
  914. SysFreeString(bstrEvent);
  915. }
  916. else
  917. {
  918. bSuccess = VARIANT_FALSE;
  919. }
  920. if (!bSuccess)
  921. break;
  922. }
  923. return (bSuccess) ? S_OK : E_FAIL;
  924. }
  925. HRESULT CAutoImageResize::CEventSink::SinkEvents(IHTMLWindow3 *pWin3, int iNum, EVENTS *pEvents)
  926. {
  927. VARIANT_BOOL bSuccess = VARIANT_TRUE;
  928. for (int i=0; i<iNum; i++)
  929. {
  930. BSTR bstrEvent = SysAllocString(CAutoImageResizeEventSinkCallback::EventsToSink[(int)(pEvents[i])].pwszEventSubscribe);
  931. if (bstrEvent)
  932. {
  933. pWin3->attachEvent(bstrEvent, (IDispatch *)this, &bSuccess);
  934. SysFreeString(bstrEvent);
  935. }
  936. else
  937. {
  938. bSuccess = VARIANT_FALSE;
  939. }
  940. if (!bSuccess)
  941. break;
  942. }
  943. return (bSuccess) ? S_OK : E_FAIL;
  944. }
  945. HRESULT CAutoImageResize::CEventSink::UnSinkEvents(IHTMLElement2 *pEle2, int iNum, EVENTS *pEvents)
  946. {
  947. for (int i=0; i<iNum; i++)
  948. {
  949. BSTR bstrEvent = SysAllocString(CAutoImageResizeEventSinkCallback::EventsToSink[(int)(pEvents[i])].pwszEventSubscribe);
  950. if (bstrEvent)
  951. {
  952. pEle2->detachEvent(bstrEvent, (IDispatch *)this);
  953. SysFreeString(bstrEvent);
  954. }
  955. }
  956. return S_OK;
  957. }
  958. HRESULT CAutoImageResize::CEventSink::UnSinkEvents(IHTMLWindow3 *pWin3, int iNum, EVENTS *pEvents)
  959. {
  960. for (int i=0; i<iNum; i++)
  961. {
  962. BSTR bstrEvent = SysAllocString(CAutoImageResizeEventSinkCallback::EventsToSink[(int)(pEvents[i])].pwszEventSubscribe);
  963. if (bstrEvent)
  964. {
  965. pWin3->detachEvent(bstrEvent, (IDispatch *)this);
  966. SysFreeString(bstrEvent);
  967. }
  968. }
  969. return S_OK;
  970. }
  971. // IDispatch
  972. STDMETHODIMP CAutoImageResize::CEventSink::GetTypeInfoCount(UINT* /*pctinfo*/)
  973. {
  974. return E_NOTIMPL;
  975. }
  976. STDMETHODIMP CAutoImageResize::CEventSink::GetTypeInfo(/* [in] */ UINT /*iTInfo*/,
  977. /* [in] */ LCID /*lcid*/,
  978. /* [out] */ ITypeInfo** /*ppTInfo*/)
  979. {
  980. return E_NOTIMPL;
  981. }
  982. STDMETHODIMP CAutoImageResize::CEventSink::GetIDsOfNames(
  983. REFIID riid,
  984. OLECHAR** rgszNames,
  985. UINT cNames,
  986. LCID lcid,
  987. DISPID* rgDispId)
  988. {
  989. return E_NOTIMPL;
  990. }
  991. STDMETHODIMP CAutoImageResize::CEventSink::Invoke(
  992. DISPID dispIdMember,
  993. REFIID, LCID,
  994. WORD wFlags,
  995. DISPPARAMS* pDispParams,
  996. VARIANT* pVarResult,
  997. EXCEPINFO*,
  998. UINT* puArgErr)
  999. {
  1000. if (m_pParent && pDispParams && pDispParams->cArgs>=1)
  1001. {
  1002. if (pDispParams->rgvarg[0].vt == VT_DISPATCH)
  1003. {
  1004. IHTMLEventObj *pObj=NULL;
  1005. if (SUCCEEDED(pDispParams->rgvarg[0].pdispVal->QueryInterface(IID_IHTMLEventObj, (void **)&pObj) && pObj))
  1006. {
  1007. EVENTS Event=EVENT_BOGUS;
  1008. BSTR bstrEvent=NULL;
  1009. pObj->get_type(&bstrEvent);
  1010. if (bstrEvent)
  1011. {
  1012. for (int i=0; i<ARRAYSIZE(CAutoImageResizeEventSinkCallback::EventsToSink); i++)
  1013. {
  1014. if (!StrCmpCW(bstrEvent, CAutoImageResizeEventSinkCallback::EventsToSink[i].pwszEventName))
  1015. {
  1016. Event = (EVENTS) i;
  1017. break;
  1018. }
  1019. }
  1020. SysFreeString(bstrEvent);
  1021. }
  1022. if (Event != EVENT_BOGUS)
  1023. {
  1024. IHTMLElement *pEle=NULL;
  1025. pObj->get_srcElement(&pEle);
  1026. // EVENT_SCROLL comes from our window so we won't have an
  1027. // element for it
  1028. if (pEle || (Event == EVENT_SCROLL) || (Event == EVENT_RESIZE) || (Event == EVENT_BEFOREPRINT) || (Event == EVENT_AFTERPRINT))
  1029. {
  1030. // Call the event handler here
  1031. m_pParent->HandleEvent(pEle, Event, pObj);
  1032. if (pEle)
  1033. {
  1034. pEle->Release();
  1035. }
  1036. }
  1037. }
  1038. pObj->Release();
  1039. }
  1040. }
  1041. }
  1042. return S_OK;
  1043. }
  1044. #undef TF_AIRESIZE