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.

5974 lines
181 KiB

  1. #include "precomp.h"
  2. #include "PrevWnd.h"
  3. #include "PrevCtrl.h"
  4. #include "resource.h"
  5. #include <shimgdata.h>
  6. #include "shutil.h"
  7. #include "tasks.h"
  8. #include <shellp.h>
  9. #include <ccstock2.h>
  10. #include <htmlhelp.h>
  11. #include "prwiziid.h"
  12. #pragma hdrstop
  13. #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
  14. #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
  15. #define COPYDATATYPE_DATAOBJECT 1
  16. #define COPYDATATYPE_FILENAME 2
  17. int g_x = 0, g_y = 0; // mouse coordinates
  18. BOOL g_bMirroredOS = FALSE;
  19. #define HTMLHELP_FILENAME TEXT("ImgPrev.chm")
  20. static COLORREF g_crCustomColors[] = {
  21. RGB(255,255,255),
  22. RGB(255,255,255),
  23. RGB(255,255,255),
  24. RGB(255,255,255),
  25. RGB(255,255,255),
  26. RGB(255,255,255),
  27. RGB(255,255,255),
  28. RGB(255,255,255),
  29. RGB(255,255,255),
  30. RGB(255,255,255),
  31. RGB(255,255,255),
  32. RGB(255,255,255),
  33. RGB(255,255,255),
  34. RGB(255,255,255),
  35. RGB(255,255,255),
  36. RGB(255,255,255)
  37. };
  38. static void _RotateRect(CRect &rect, CAnnotation* pAnnotation)
  39. {
  40. UINT uType = pAnnotation->GetType();
  41. if (uType != MT_TYPEDTEXT && uType != MT_FILETEXT && uType != MT_STAMP && uType != MT_ATTACHANOTE)
  42. return;
  43. CTextAnnotation* pTextAnnotation = (CTextAnnotation*)pAnnotation;
  44. int nOrientation = pTextAnnotation->GetOrientation();
  45. if (nOrientation == 900 || nOrientation == 2700)
  46. {
  47. int nWidth = rect.Width();
  48. int nHeight = rect.Height();
  49. rect.right = rect.left + nHeight;
  50. rect.bottom = rect.top + nWidth;
  51. }
  52. }
  53. CPreviewWnd::CPreviewWnd() : m_ctlToolbar(NULL, this, 1), m_ctlPreview(this), m_ctlEdit(NULL, this, 2)
  54. {
  55. // we are often created on the stack, so we can't be sure that we're zero initialized
  56. m_fCanCrop = FALSE;
  57. m_fCropping = FALSE;
  58. m_rectCropping.SetRectEmpty();
  59. m_fBusy = FALSE;
  60. m_hCurOld = NULL;
  61. m_hCurrent = NULL;
  62. m_fWarnQuietSave = TRUE;
  63. m_fWarnNoSave = TRUE;
  64. m_fPromptingUser = FALSE;
  65. m_fCanAnnotate = FALSE;
  66. m_fAnnotating = FALSE;
  67. m_fEditingAnnotation = FALSE;
  68. m_fDirty = FALSE;
  69. m_pEvents = 0;
  70. m_fPaused = FALSE;
  71. m_fGoBack = FALSE;
  72. m_fHidePrintBtn = FALSE;
  73. m_fPrintable = FALSE;
  74. m_fDisableEdit = FALSE;
  75. m_fCanSave = TRUE;
  76. m_fExitApp = FALSE;
  77. m_fAllowContextMenu = TRUE; // full screen window always has a context menu
  78. m_iCurSlide = -1;
  79. m_iDecodingNextImage = -1;
  80. m_pNextImageData = NULL;
  81. m_fToolbarHidden = TRUE;
  82. m_dwMultiPageMode = MPCMD_HIDDEN;
  83. m_fIgnoreUITimers = FALSE;
  84. DWORD cbSize = sizeof(m_uTimeout);
  85. UINT uDefault = DEFAULT_SHIMGVW_TIMEOUT;
  86. SHRegGetUSValue(REGSTR_SHIMGVW, REGSTR_TIMEOUT, NULL, (void *)&m_uTimeout, &cbSize, FALSE, (void *)&uDefault, sizeof(uDefault));
  87. InitSelectionTracking();
  88. g_bMirroredOS = IS_MIRRORING_ENABLED(); // global????
  89. m_hdpaSelectedAnnotations = NULL;
  90. m_haccel = NULL;
  91. m_hpal = NULL;
  92. m_dwMode = 0;
  93. m_fShowToolbar = TRUE;
  94. m_punkSite = NULL;
  95. m_pImageFactory = NULL;
  96. m_pcwndSlideShow = NULL;
  97. m_hFont = NULL;
  98. m_pImageData = NULL;
  99. m_ppidls = NULL;
  100. m_cItems = 0;
  101. _pcm3 = NULL;
  102. m_pTaskScheduler = NULL;
  103. m_pici = NULL;
  104. _pdtobj = NULL;
  105. m_fFirstTime = TRUE;
  106. m_fFirstItem = FALSE;
  107. m_dwEffect = DROPEFFECT_NONE;
  108. m_fIgnoreNextNotify = FALSE;
  109. m_uRegister = 0;
  110. m_fNoRestore = FALSE;
  111. m_bRTLMirrored = FALSE;
  112. m_cWalkDepth = 0;
  113. }
  114. HRESULT CPreviewWnd::Initialize(CPreviewWnd* pother, DWORD dwMode, BOOL bExitApp)
  115. {
  116. HRESULT hr = E_OUTOFMEMORY;
  117. m_hdpaSelectedAnnotations = DPA_Create(16);
  118. if (m_hdpaSelectedAnnotations)
  119. {
  120. hr = S_OK;
  121. m_dwMode = dwMode;
  122. m_fExitApp = bExitApp;
  123. // Set some defaults based on the mode
  124. if (CONTROL_MODE == m_dwMode)
  125. {
  126. m_fHidePrintBtn = TRUE;
  127. }
  128. if (pother)
  129. {
  130. m_fHidePrintBtn = pother->m_fHidePrintBtn;
  131. m_fPrintable = pother->m_fPrintable;
  132. m_fDisableEdit = pother->m_fDisableEdit;
  133. m_fCanSave = pother->m_fCanSave;
  134. m_haccel = pother->m_haccel;
  135. m_dwMultiPageMode = pother->m_dwMultiPageMode;
  136. m_hpal = pother->m_hpal;
  137. m_iCurSlide = pother->m_iCurSlide;
  138. m_uTimeout = pother->m_uTimeout;
  139. SetSite(pother->m_punkSite);
  140. // we grab a reference to the controlling objects m_pImageFactory
  141. // becaue it would be odd to create new ones.
  142. m_pImageFactory = pother->m_pImageFactory;
  143. if (m_pImageFactory)
  144. {
  145. m_pImageFactory->AddRef();
  146. }
  147. m_pTaskScheduler = pother->m_pTaskScheduler;
  148. if (m_pTaskScheduler)
  149. {
  150. m_pTaskScheduler->AddRef();
  151. }
  152. // lets copy the DPA of items also, and the current index
  153. if (pother->m_ppidls)
  154. {
  155. m_ppidls = (LPITEMIDLIST*)CoTaskMemAlloc(sizeof(LPITEMIDLIST)*pother->m_cItems);
  156. if (m_ppidls)
  157. {
  158. for (int iItem = 0; iItem != pother->m_cItems; iItem++)
  159. {
  160. if (SUCCEEDED(pother->_GetItem(iItem, &m_ppidls[m_cItems])))
  161. {
  162. m_cItems++;
  163. }
  164. }
  165. }
  166. }
  167. }
  168. }
  169. return hr;
  170. }
  171. int ClearCB(void *p, void *pData);
  172. CPreviewWnd::~CPreviewWnd()
  173. {
  174. CleanupSelectionTracking();
  175. if (m_hdpaSelectedAnnotations != NULL)
  176. DPA_Destroy(m_hdpaSelectedAnnotations);
  177. ::DeleteObject(m_hFont);
  178. ATOMICRELEASE(m_pImageData);
  179. ATOMICRELEASE(m_pNextImageData);
  180. ATOMICRELEASE(m_pImageFactory);
  181. SetSite(NULL);
  182. ATOMICRELEASE(_pdtobj);
  183. ATOMICRELEASE(m_pTaskScheduler);
  184. _ClearDPA();
  185. if (m_pcwndSlideShow)
  186. {
  187. if (m_pcwndSlideShow->m_hWnd)
  188. {
  189. m_pcwndSlideShow->DestroyWindow();
  190. }
  191. delete m_pcwndSlideShow;
  192. }
  193. if (m_pici)
  194. {
  195. LocalFree(m_pici);
  196. m_pici = NULL;
  197. }
  198. }
  199. BOOL CPreviewWnd::CreateSlideshowWindow(UINT cWalkDepth)
  200. {
  201. RECT rc = { CW_USEDEFAULT, CW_USEDEFAULT, 0, 0 };
  202. if (!Create(NULL, rc, NULL, WS_VISIBLE | WS_POPUP | WS_CLIPCHILDREN))
  203. return FALSE;
  204. WINDOWPLACEMENT wp = {0};
  205. wp.length = sizeof(wp);
  206. GetWindowPlacement(&wp);
  207. wp.showCmd = SW_MAXIMIZE;
  208. SetWindowPlacement(&wp);
  209. SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_SHOWWINDOW);
  210. // when we get called from autoplay to do a slideshow,
  211. // we need to walk deeply to find everything
  212. // that the autoplay code may have found
  213. m_cWalkDepth = cWalkDepth;
  214. return TRUE;
  215. }
  216. BOOL CPreviewWnd::_CloseSlideshowWindow()
  217. {
  218. if (m_fExitApp)
  219. PostQuitMessage(0);
  220. else
  221. PostMessage(WM_CLOSE, 0, 0);
  222. return TRUE;
  223. }
  224. BOOL CPreviewWnd::CreateViewerWindow()
  225. {
  226. // create the window hidden, that way any sizing etc we perform doesn't reflect
  227. // until its actually visible.
  228. RECT rc = { CW_USEDEFAULT, CW_USEDEFAULT, 0, 0 };
  229. BOOL bRet = (NULL != Create(NULL, rc, NULL, WS_OVERLAPPEDWINDOW));
  230. m_haccel = LoadAccelerators(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDA_PREVWND_SINGLEPAGE));
  231. if (bRet)
  232. {
  233. // restore the window size based on the information we store in the registry.
  234. HKEY hk;
  235. if (ERROR_SUCCESS == RegOpenKey(HKEY_CURRENT_USER, REGSTR_SHIMGVW, &hk))
  236. {
  237. DWORD cbSize, dwType;
  238. // set the window placement, passing the restore rectangle for the window.
  239. WINDOWPLACEMENT wp = { 0 };
  240. wp.length = sizeof(wp);
  241. GetWindowPlacement(&wp);
  242. cbSize = sizeof(wp.rcNormalPosition);
  243. RegQueryValueEx(hk, REGSTR_BOUNDS, NULL, &dwType, (BYTE*)&wp.rcNormalPosition, &cbSize);
  244. BOOL fMaximize = TRUE;
  245. cbSize = sizeof(fMaximize);
  246. RegQueryValueEx(hk, REGSTR_MAXIMIZED, NULL, &dwType, (BYTE*)&fMaximize, &cbSize);
  247. if (fMaximize)
  248. wp.showCmd = SW_MAXIMIZE;
  249. SetWindowPlacement(&wp);
  250. RegCloseKey(hk);
  251. }
  252. // now show the window having set its placement etc.
  253. SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_SHOWWINDOW);
  254. }
  255. return bRet;
  256. }
  257. void ReplaceWindowIcon(HWND hwnd, int id, HICON hicon)
  258. {
  259. HICON hiconOld = (HICON)SendMessage(hwnd, WM_SETICON, id, (LPARAM)hicon);
  260. if (hiconOld)
  261. DestroyIcon(hiconOld);
  262. }
  263. LRESULT CPreviewWnd::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&)
  264. {
  265. HRESULT hr = S_OK;
  266. if (IS_BIDI_LOCALIZED_SYSTEM())
  267. {
  268. SHSetWindowBits(m_hWnd, GWL_EXSTYLE, WS_EX_LAYOUTRTL, WS_EX_LAYOUTRTL);
  269. m_bRTLMirrored = TRUE;
  270. }
  271. if (!m_pImageFactory)
  272. {
  273. hr = CoCreateInstance(CLSID_ShellImageDataFactory, NULL, CLSCTX_INPROC,
  274. IID_PPV_ARG(IShellImageDataFactory, &m_pImageFactory));
  275. if (FAILED(hr))
  276. return -1;
  277. }
  278. if (!m_pTaskScheduler)
  279. {
  280. hr = IUnknown_QueryService(m_punkSite, SID_ShellTaskScheduler, IID_PPV_ARG(IShellTaskScheduler, &m_pTaskScheduler));
  281. if (FAILED(hr))
  282. {
  283. hr = CoCreateInstance(CLSID_ShellTaskScheduler, NULL, CLSCTX_INPROC,
  284. IID_PPV_ARG(IShellTaskScheduler, &m_pTaskScheduler));
  285. if (FAILED(hr))
  286. return -1;
  287. }
  288. }
  289. // figure out where to place the zoom window
  290. RECT rcWnd;
  291. GetClientRect(&rcWnd);
  292. if (m_fShowToolbar)
  293. {
  294. // Create a toolbar control and then subclass it
  295. if (!CreateToolbar())
  296. return -1;
  297. m_iSSToolbarSelect = 0;
  298. }
  299. HICON hicon = LoadIcon(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDI_FULLSCREEN));
  300. ReplaceWindowIcon(m_hWnd, ICON_SMALL, hicon);
  301. ReplaceWindowIcon(m_hWnd, ICON_BIG, hicon);
  302. // Create the preview window
  303. DWORD dwExStyle = 0; // (WINDOW_MODE == m_dwMode) ? WS_EX_CLIENTEDGE : 0 ;
  304. if (m_ctlPreview.Create(m_hWnd, rcWnd, NULL, WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, dwExStyle))
  305. {
  306. // When the window is created its default mode should be NOACTION. This call is needed
  307. // because the object might have a longer life cycle than the window. If a new window
  308. // is created for the same object we want to reset the state.
  309. m_ctlPreview.SetMode(CZoomWnd::MODE_NOACTION);
  310. m_ctlPreview.SetScheduler(m_pTaskScheduler);
  311. }
  312. RegisterDragDrop(m_hWnd, SAFECAST(this, IDropTarget *));
  313. return 0;
  314. }
  315. HRESULT CPreviewWnd::_SaveIfDirty(BOOL fCanCancel)
  316. {
  317. // Callers assume that _SaveIfDirty will either return S_OK or S_FALSE
  318. // since this function is designed to sit in a loop until the user gives
  319. // up saving (cancels) or save successfully.
  320. HRESULT hr = S_OK;
  321. if (m_fDirty)
  322. {
  323. CComBSTR bstrMsg, bstrTitle;
  324. if (bstrMsg.LoadString(IDS_SAVEWARNING_MSGBOX) && bstrTitle.LoadString(IDS_PROJNAME))
  325. {
  326. hr = E_FAIL;
  327. while (FAILED(hr))
  328. {
  329. UINT uFlags;
  330. if (fCanCancel)
  331. uFlags = MB_YESNOCANCEL;
  332. else
  333. uFlags = MB_YESNO;
  334. uFlags |= MB_ICONQUESTION | MB_DEFBUTTON1 | MB_APPLMODAL;
  335. m_fPromptingUser = TRUE;
  336. int iResult = MessageBox(bstrMsg, bstrTitle, uFlags);
  337. m_fPromptingUser = FALSE;
  338. if (iResult == IDYES)
  339. {
  340. // if this fails we keep looping.
  341. // if this returns S_OK we succeed
  342. // if this returns S_FALSE we cancel
  343. hr = _SaveAsCmd();
  344. }
  345. else if (iResult == IDCANCEL)
  346. {
  347. hr = S_FALSE;
  348. }
  349. else
  350. {
  351. hr = S_OK;
  352. }
  353. }
  354. }
  355. if (S_OK == hr)
  356. m_fDirty = FALSE;
  357. }
  358. return hr;
  359. }
  360. LRESULT CPreviewWnd::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled)
  361. {
  362. // hack alert- if CONTROL is held down while pressing the close button, do the registry stuff.
  363. // make sure the E accelerator isn't being used (edit verb)!
  364. if (m_fPromptingUser)
  365. {
  366. SetForegroundWindow(m_hWnd);
  367. fHandled = TRUE;
  368. return 0;
  369. }
  370. if (!m_fNoRestore && GetKeyState(VK_CONTROL) & 0x8000)
  371. {
  372. CRegKey Key;
  373. if (ERROR_SUCCESS == Key.Open(HKEY_CURRENT_USER, REGSTR_SHIMGVW))
  374. {
  375. Key.DeleteValue(REGSTR_LOSSYROTATE);
  376. }
  377. if (ERROR_SUCCESS == Key.Open(HKEY_CURRENT_USER, REGSTR_DONTSHOWME))
  378. {
  379. Key.DeleteValue(REGSTR_SAVELESS);
  380. Key.DeleteValue(REGSTR_LOSSYROTATE);
  381. }
  382. CComBSTR bstrMsg, bstrTitle;
  383. if (bstrMsg.LoadString(IDS_RESET_MSGBOX) && bstrTitle.LoadString(IDS_PROJNAME))
  384. {
  385. m_fPromptingUser = TRUE;
  386. MessageBox(bstrMsg, bstrTitle, MB_OK | MB_APPLMODAL);
  387. m_fPromptingUser = FALSE;
  388. }
  389. }
  390. fHandled = FALSE; // let it close
  391. HRESULT hr = _SaveIfDirty(TRUE);
  392. if (hr == S_FALSE) // _SaveIfDirty can only return S_OK and S_FALSE
  393. {
  394. m_fNoRestore = FALSE;
  395. fHandled = TRUE;
  396. }
  397. if (!fHandled)
  398. {
  399. m_fClosed = TRUE;
  400. }
  401. return 0;
  402. }
  403. // we only have to erase the portion not covered by the zoomwnd
  404. // change this code if the toolbar is put back at the top of the window
  405. LRESULT CPreviewWnd::OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled)
  406. {
  407. RECT rc;
  408. RECT rcZoomwnd;
  409. m_ctlPreview.GetClientRect(&rcZoomwnd);
  410. GetClientRect(&rc);
  411. rc.top = RECTHEIGHT(rcZoomwnd);
  412. SetBkColor((HDC)wParam, m_ctlPreview.GetBackgroundColor());
  413. ExtTextOut((HDC)wParam, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  414. fHandled = TRUE;
  415. return TRUE;
  416. }
  417. LRESULT CPreviewWnd::OnSize(UINT , WPARAM wParam, LPARAM lParam, BOOL&)
  418. {
  419. int x =0, y =0, cx =0, cy =0;
  420. if (lParam == 0)
  421. {
  422. RECT rcClient;
  423. GetClientRect(&rcClient);
  424. cx = RECTWIDTH(rcClient);
  425. cy = RECTHEIGHT(rcClient);
  426. }
  427. else
  428. {
  429. cx = GET_X_LPARAM(lParam);
  430. cy = GET_Y_LPARAM(lParam);
  431. }
  432. if (m_fShowToolbar)
  433. {
  434. SIZE sizeToolbar;
  435. m_ctlToolbar.SendMessage(TB_GETMAXSIZE, 0, (LPARAM)&sizeToolbar);
  436. if (sizeToolbar.cx > cx)
  437. sizeToolbar.cx = cx;
  438. if (SLIDESHOW_MODE != m_dwMode)
  439. {
  440. // Center the toolbar horizontally
  441. LONG cyBottomMargin = (CONTROL_MODE == m_dwMode) ? NEWTOOLBAR_BOTTOMMARGIN_CTRLMODE : NEWTOOLBAR_BOTTOMMARGIN;
  442. LONG xNewToolbar = ( cx - sizeToolbar.cx ) / 2;
  443. LONG yNewToolbar = cy - ( cyBottomMargin + sizeToolbar.cy );
  444. ::SetWindowPos(m_ctlToolbar.m_hWnd, NULL, xNewToolbar, yNewToolbar, sizeToolbar.cx, sizeToolbar.cy, SWP_NOZORDER);
  445. // make the preview window shorter so the toolbar is below it
  446. cy -= ( NEWTOOLBAR_TOPMARGIN + sizeToolbar.cy + cyBottomMargin);
  447. }
  448. else
  449. {
  450. // Pin the toolbar to the upper right corner
  451. UINT uFlags = 0;
  452. if (m_fToolbarHidden)
  453. uFlags |= SWP_HIDEWINDOW;
  454. else
  455. uFlags |= SWP_SHOWWINDOW;
  456. ::SetWindowPos(m_ctlToolbar.m_hWnd, HWND_TOP, cx-sizeToolbar.cx, 0, sizeToolbar.cx, sizeToolbar.cy, uFlags);
  457. }
  458. }
  459. ::SetWindowPos(m_ctlPreview.m_hWnd, NULL, x, y, cx, cy, SWP_NOZORDER);
  460. return 0;
  461. }
  462. BOOL CPreviewWnd::_VerbExists(LPCTSTR pszVerb)
  463. {
  464. // TODO: Create the context menu for the item and check it for the verb
  465. return TRUE;
  466. }
  467. // given a verb lets invoke it for the current file
  468. HRESULT CPreviewWnd::_InvokeVerb(LPCTSTR pszVerb, LPCTSTR szParameters)
  469. {
  470. SHELLEXECUTEINFO sei = {0};
  471. sei.cbSize = sizeof(sei);
  472. sei.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_HMONITOR;
  473. sei.hwnd = m_hWnd;
  474. sei.lpVerb = pszVerb;
  475. sei.nShow = SW_SHOW;
  476. sei.lpParameters = szParameters;
  477. sei.hMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST);
  478. LPITEMIDLIST pidl = NULL;
  479. TCHAR szPath[MAX_PATH];
  480. HRESULT hr = GetCurrentIDList(&pidl);
  481. if (SUCCEEDED(hr))
  482. {
  483. sei.lpIDList = pidl;
  484. }
  485. else if (SUCCEEDED(hr = PathFromImageData(szPath, ARRAYSIZE(szPath))))
  486. {
  487. sei.lpFile = szPath;
  488. }
  489. if (SUCCEEDED(hr))
  490. {
  491. hr = S_OK;
  492. if (!ShellExecuteEx(&sei))
  493. hr = E_FAIL;
  494. }
  495. ILFree(pidl);
  496. return hr;
  497. }
  498. // show the window and activate it
  499. // if the window is minimized, restore it
  500. void RestoreAndActivate(HWND hwnd)
  501. {
  502. if (IsIconic(hwnd))
  503. {
  504. ShowWindow(hwnd, SW_RESTORE);
  505. }
  506. SetForegroundWindow(hwnd);
  507. }
  508. // Handles WM_COMMAND messages sent from the toolbar control
  509. LRESULT CPreviewWnd::OnToolbarCommand(WORD wNotifyCode, WORD wID, HWND hwnd, BOOL& fHandled)
  510. {
  511. switch (wID)
  512. {
  513. case ID_ZOOMINCMD:
  514. ZoomIn();
  515. break;
  516. case ID_ZOOMOUTCMD:
  517. ZoomOut();
  518. break;
  519. case ID_SELECTCMD:
  520. if (m_fCanAnnotate)
  521. {
  522. _UpdateButtons(wID);
  523. }
  524. break;
  525. case ID_CROPCMD:
  526. if (m_fCanCrop)
  527. {
  528. m_rectCropping.SetRectEmpty();
  529. _UpdateButtons(wID);
  530. }
  531. break;
  532. case ID_ACTUALSIZECMD:
  533. ActualSize();
  534. break;
  535. case ID_BESTFITCMD:
  536. BestFit();
  537. break;
  538. case ID_PRINTCMD:
  539. _RefreshSelection(FALSE);
  540. _InvokePrintWizard();
  541. break;
  542. case ID_PREVPAGECMD:
  543. case ID_NEXTPAGECMD:
  544. _PrevNextPage(ID_NEXTPAGECMD==wID);
  545. break;
  546. case ID_NEXTIMGCMD:
  547. case ID_PREVIMGCMD:
  548. _RefreshSelection(FALSE);
  549. if (WINDOW_MODE == m_dwMode)
  550. {
  551. HRESULT hr = _SaveIfDirty(TRUE);
  552. if (hr == S_FALSE)
  553. return 0;
  554. _ShowNextSlide(ID_PREVIMGCMD == wID);
  555. }
  556. else if (m_punkSite)
  557. {
  558. IFolderView* pfv;
  559. if (SUCCEEDED(IUnknown_QueryService(m_punkSite, SID_DefView, IID_PPV_ARG(IFolderView, &pfv))))
  560. {
  561. int iCurrent, cItems;
  562. if (SUCCEEDED(pfv->ItemCount(SVGIO_ALLVIEW, &cItems)) && (cItems > 1) &&
  563. SUCCEEDED(pfv->GetFocusedItem(&iCurrent)))
  564. {
  565. int iToSelect = iCurrent + ((ID_PREVIMGCMD == wID) ? -1 : 1);
  566. if (iToSelect < 0)
  567. {
  568. iToSelect = cItems-1;
  569. }
  570. else if (iToSelect >= cItems)
  571. {
  572. iToSelect = 0;
  573. }
  574. pfv->SelectItem(iToSelect, SVSI_SELECTIONMARK | SVSI_SELECT
  575. | SVSI_ENSUREVISIBLE | SVSI_DESELECTOTHERS | SVSI_FOCUSED);
  576. }
  577. pfv->Release();
  578. }
  579. }
  580. break;
  581. case ID_FREEHANDCMD:
  582. case ID_HIGHLIGHTCMD:
  583. case ID_LINECMD:
  584. case ID_FRAMECMD:
  585. case ID_RECTCMD:
  586. case ID_TEXTCMD:
  587. case ID_NOTECMD:
  588. if (m_fCanAnnotate)
  589. {
  590. _UpdateButtons(wID);
  591. }
  592. break;
  593. case ID_PROPERTIESCMD:
  594. _UpdateButtons(wID);
  595. _PropertiesCmd();
  596. break;
  597. case ID_SAVEASCMD:
  598. _UpdateButtons(wID);
  599. _SaveAsCmd();
  600. break;
  601. case ID_EDITCMD:
  602. _UpdateButtons(wID);
  603. if (m_fCanAnnotate && m_fAnnotating)
  604. {
  605. _StartEditing();
  606. }
  607. break;
  608. case ID_HELPCMD:
  609. _UpdateButtons(wID);
  610. HtmlHelp(::GetDesktopWindow(), HTMLHELP_FILENAME, HH_DISPLAY_TOPIC, NULL);
  611. break;
  612. case ID_OPENCMD:
  613. _UpdateButtons(wID);
  614. _OpenCmd();
  615. break;
  616. case ID_DELETECMD:
  617. _UpdateButtons(wID);
  618. if (m_fCanAnnotate && m_fAnnotating && DPA_GetPtrCount(m_hdpaSelectedAnnotations) > 0)
  619. {
  620. _RemoveAnnotatingSelection();
  621. }
  622. else
  623. {
  624. _DeleteCurrentSlide();
  625. }
  626. break;
  627. case ID_SLIDESHOWCMD:
  628. if (!m_fFirstTime) // don't try to do this while the namespace walk is ongoing
  629. {
  630. StartSlideShow(NULL);
  631. }
  632. break;
  633. }
  634. return 0;
  635. }
  636. // OnEditCommand
  637. //
  638. // Handles picture editting(rotate/flip/save etc) WM_COMMAND messages
  639. LRESULT CPreviewWnd::OnEditCommand(WORD , WORD wID, HWND , BOOL& )
  640. {
  641. switch (wID)
  642. {
  643. case ID_ROTATE90CMD:
  644. Rotate(90);
  645. break;
  646. case ID_ROTATE270CMD:
  647. Rotate(270);
  648. break;
  649. }
  650. return 0;
  651. }
  652. LRESULT CPreviewWnd::OnPositionCommand(WORD wNotifyCode, WORD wID, HWND hwnd, BOOL& fHandled)
  653. {
  654. if (SLIDESHOW_MODE == m_dwMode)
  655. {
  656. switch (wID)
  657. {
  658. case ID_NUDGELEFTCMD:
  659. OnSlideshowCommand(0, ID_PREVCMD, NULL, fHandled);
  660. break;
  661. case ID_NUDGERIGHTCMD:
  662. OnSlideshowCommand(0, ID_NEXTCMD, NULL, fHandled);
  663. break;
  664. default:
  665. break;
  666. }
  667. }
  668. else
  669. {
  670. if (DPA_GetPtrCount(m_hdpaSelectedAnnotations) == 0)
  671. {
  672. BOOL bDummy;
  673. switch (wID)
  674. {
  675. case ID_MOVELEFTCMD:
  676. m_ctlPreview.OnScroll(WM_HSCROLL, SB_PAGEUP, 0, fHandled);
  677. break;
  678. case ID_MOVERIGHTCMD:
  679. m_ctlPreview.OnScroll(WM_HSCROLL, SB_PAGEDOWN, 0, fHandled);
  680. break;
  681. case ID_MOVEUPCMD:
  682. m_ctlPreview.OnScroll(WM_VSCROLL, SB_PAGEUP, 0, fHandled);
  683. break;
  684. case ID_MOVEDOWNCMD:
  685. m_ctlPreview.OnScroll(WM_VSCROLL, SB_PAGEDOWN, 0, fHandled);
  686. break;
  687. case ID_NUDGELEFTCMD:
  688. if (m_ctlPreview.ScrollBarsPresent())
  689. {
  690. m_ctlPreview.OnScroll(WM_HSCROLL, SB_LINEUP, 0, fHandled);
  691. }
  692. else
  693. {
  694. OnToolbarCommand(0, ID_PREVIMGCMD, m_hWnd, bDummy);
  695. }
  696. break;
  697. case ID_NUDGERIGHTCMD:
  698. if (m_ctlPreview.ScrollBarsPresent())
  699. {
  700. m_ctlPreview.OnScroll(WM_HSCROLL, SB_LINEDOWN, 0, fHandled);
  701. }
  702. else
  703. {
  704. OnToolbarCommand(0, ID_NEXTIMGCMD, m_hWnd, bDummy);
  705. }
  706. break;
  707. case ID_NUDGEUPCMD:
  708. if (m_ctlPreview.ScrollBarsPresent())
  709. {
  710. m_ctlPreview.OnScroll(WM_VSCROLL, SB_LINEUP, 0, fHandled);
  711. }
  712. else
  713. {
  714. OnToolbarCommand(0, ID_PREVIMGCMD, m_hWnd, bDummy);
  715. }
  716. break;
  717. case ID_NUDGEDOWNCMD:
  718. if (m_ctlPreview.ScrollBarsPresent())
  719. {
  720. m_ctlPreview.OnScroll(WM_VSCROLL, SB_LINEDOWN, 0, fHandled);
  721. }
  722. else
  723. {
  724. OnToolbarCommand(0, ID_NEXTIMGCMD, m_hWnd, bDummy);
  725. }
  726. break;
  727. default:
  728. break;
  729. }
  730. }
  731. else
  732. {
  733. CRect rectImage;
  734. m_ctlPreview.GetVisibleImageWindowRect(rectImage);
  735. m_ctlPreview.GetImageFromWindow((LPPOINT)(LPRECT)rectImage, 2);
  736. rectImage.DeflateRect(5, 5);
  737. CSize size(0,0);
  738. switch (wID)
  739. {
  740. case ID_MOVELEFTCMD:
  741. size.cx = -25;
  742. break;
  743. case ID_MOVERIGHTCMD:
  744. size.cx = 25;
  745. break;
  746. case ID_MOVEUPCMD:
  747. size.cy = -25;
  748. break;
  749. case ID_MOVEDOWNCMD:
  750. size.cy = 25;
  751. break;
  752. case ID_NUDGELEFTCMD:
  753. size.cx = -1;
  754. break;
  755. case ID_NUDGERIGHTCMD:
  756. size.cx = 1;
  757. break;
  758. case ID_NUDGEUPCMD:
  759. size.cy = -1;
  760. break;
  761. case ID_NUDGEDOWNCMD:
  762. size.cy = 1;
  763. break;
  764. default:
  765. break;
  766. }
  767. if (size.cx == 0 && size.cy == 0)
  768. return 0;
  769. _UpdateAnnotatingSelection();
  770. CRect rect;
  771. CRect rectNewPos;
  772. BOOL bValidMove = TRUE;
  773. for (int i = 0; i < DPA_GetPtrCount(m_hdpaSelectedAnnotations); i++)
  774. {
  775. CAnnotation* pAnnotation = (CAnnotation*)DPA_GetPtr(m_hdpaSelectedAnnotations, i);
  776. pAnnotation->GetRect(rect);
  777. rect.NormalizeRect();
  778. rect.OffsetRect(size);
  779. if (!rectNewPos.IntersectRect(rectImage, rect))
  780. bValidMove = FALSE;
  781. }
  782. if (!bValidMove)
  783. return 0;
  784. for (int i = 0; i < DPA_GetPtrCount(m_hdpaSelectedAnnotations); i++)
  785. {
  786. CAnnotation* pAnnotation = (CAnnotation*)DPA_GetPtr(m_hdpaSelectedAnnotations, i);
  787. pAnnotation->Move(size);
  788. }
  789. m_fDirty = TRUE;
  790. _UpdateAnnotatingSelection();
  791. }
  792. }
  793. return 0;
  794. }
  795. // call SetNewImage when the entire image has changed, call UpdateImage if it's the same image
  796. // but it needs to be updated
  797. void CPreviewWnd::_SetNewImage(CDecodeTask * pData)
  798. {
  799. // store the new pointer
  800. if (m_pImageData)
  801. {
  802. _SaveIfDirty();
  803. // m_pImageData might be NULL after _SaveAsCmd
  804. ATOMICRELEASE(m_pImageData);
  805. }
  806. m_pImageData = pData;
  807. m_fWarnQuietSave = TRUE; // Reset for each image
  808. m_fWarnNoSave = TRUE;
  809. if (!m_pImageData)
  810. {
  811. StatusUpdate(IDS_LOADFAILED);
  812. return;
  813. }
  814. m_pImageData->AddRef();
  815. // Even if m_hpal is NULL it is still correct, so we always go ahead and set it.
  816. m_ctlPreview.SetPalette(m_hpal);
  817. if (SLIDESHOW_MODE != m_dwMode)
  818. {
  819. // update toolbar state
  820. _SetMultipageCommands();
  821. _SetMultiImagesCommands();
  822. BOOL fCanAnnotate = _CanAnnotate(m_pImageData);
  823. _SetAnnotatingCommands(fCanAnnotate);
  824. BOOL fCanCrop = _CanCrop(m_pImageData);
  825. _SetCroppingCommands(fCanCrop);
  826. _RefreshSelection(TRUE);
  827. _SetEditCommands();
  828. m_fPrintable = _VerbExists(TEXT("print"));
  829. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_PRINTCMD, MAKELONG(m_fPrintable, 0));
  830. // we need to watch non-TIFFs for changes so we can reload.
  831. // TIFFs are problematic because we allow annotations, and reloading during annotation
  832. // would suck
  833. if (CONTROL_MODE != m_dwMode)
  834. {
  835. _RegisterForChangeNotify(TRUE);
  836. }
  837. }
  838. // notify our child
  839. m_ctlPreview.SetImageData(m_pImageData, TRUE);
  840. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_ACTUALSIZECMD, MAKELONG(TRUE, 0));
  841. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_BESTFITCMD, MAKELONG(FALSE, 0));
  842. // update our toolbar
  843. BOOL fHandled;
  844. OnSize(0x0, 0, 0, fHandled);
  845. }
  846. // for refreshing the current m_pImageData because it has changed in some
  847. // way, i.e. it has advanced to the next frame, the next page, or was edited.
  848. void CPreviewWnd::_UpdateImage()
  849. {
  850. _RefreshSelection(TRUE);
  851. m_ctlPreview.SetImageData(m_pImageData, FALSE);
  852. }
  853. // Handles slidwshow (pause/resume, next/previous etc) WM_COMMAND messages
  854. void CPreviewWnd::TogglePlayState()
  855. {
  856. if (!m_fPaused)
  857. {
  858. KillTimer(TIMER_SLIDESHOW);
  859. }
  860. else
  861. {
  862. SetTimer(TIMER_SLIDESHOW, m_uTimeout);
  863. }
  864. m_fPaused = !m_fPaused;
  865. WPARAM wpCheck, wpUncheck;
  866. if (m_fPaused)
  867. {
  868. wpCheck = ID_PAUSECMD;
  869. wpUncheck = ID_PLAYCMD;
  870. }
  871. else
  872. {
  873. wpCheck = ID_PLAYCMD;
  874. wpUncheck = ID_PAUSECMD;
  875. }
  876. m_ctlToolbar.SendMessage(TB_SETSTATE, wpCheck, TBSTATE_ENABLED | TBSTATE_CHECKED);
  877. m_ctlToolbar.SendMessage(TB_SETSTATE, wpUncheck, TBSTATE_ENABLED);
  878. }
  879. LRESULT CPreviewWnd::OnMenuMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled)
  880. {
  881. if (_pcm3)
  882. _pcm3->HandleMenuMsg(uMsg, wParam, lParam);
  883. return 0;
  884. }
  885. LRESULT CPreviewWnd::OnAppCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled)
  886. {
  887. UINT cmd = GET_APPCOMMAND_LPARAM(lParam);
  888. DWORD dwKeys = GET_KEYSTATE_LPARAM(lParam);
  889. switch (cmd)
  890. {
  891. case APPCOMMAND_BROWSER_FORWARD:
  892. if (SLIDESHOW_MODE == m_dwMode)
  893. OnSlideshowCommand(0, ID_NEXTCMD, NULL, fHandled);
  894. else
  895. {
  896. if ((dwKeys & MK_CONTROL) || (m_pImageData && !m_pImageData->IsMultipage()))
  897. OnToolbarCommand(0, ID_NEXTIMGCMD, NULL, fHandled);
  898. else
  899. NextPage();
  900. }
  901. break;
  902. case APPCOMMAND_BROWSER_BACKWARD:
  903. if (SLIDESHOW_MODE == m_dwMode)
  904. OnSlideshowCommand(0, ID_PREVCMD, NULL, fHandled);
  905. else
  906. {
  907. if ((dwKeys & MK_CONTROL) || (m_pImageData && !m_pImageData->IsMultipage()))
  908. OnToolbarCommand(0, ID_PREVIMGCMD, NULL, fHandled);
  909. else
  910. PreviousPage();
  911. }
  912. break;
  913. default:
  914. fHandled = FALSE;
  915. }
  916. return 0;
  917. }
  918. LRESULT CPreviewWnd::OnSlideshowCommand(WORD wNotifyCode, WORD wID, HWND hwnd, BOOL& fHandled)
  919. {
  920. switch (wID)
  921. {
  922. case ID_PLAYCMD:
  923. m_iSSToolbarSelect = 0;
  924. if (m_fPaused)
  925. {
  926. m_fGoBack = FALSE;
  927. TogglePlayState();
  928. _ShowNextSlide(m_fGoBack);
  929. }
  930. fHandled = TRUE;
  931. break;
  932. case ID_PAUSECMD:
  933. m_iSSToolbarSelect = 1;
  934. if (!m_fPaused)
  935. {
  936. TogglePlayState();
  937. }
  938. fHandled = TRUE;
  939. break;
  940. case ID_NEXTCMD:
  941. case ID_PREVCMD:
  942. if (wID == ID_PREVCMD)
  943. {
  944. m_iSSToolbarSelect = 3;
  945. m_fGoBack = TRUE;
  946. }
  947. else
  948. {
  949. m_iSSToolbarSelect = 4;
  950. m_fGoBack = FALSE;
  951. }
  952. _ShowNextSlide(m_fGoBack);
  953. fHandled = TRUE;
  954. break;
  955. case ID_CLOSECMD:
  956. m_iSSToolbarSelect = 6;
  957. _CloseSlideshowWindow();
  958. break;
  959. }
  960. return 0;
  961. }
  962. BOOL CPreviewWnd::CreateToolbar()
  963. {
  964. // ensure that the common controls are initialized
  965. INITCOMMONCONTROLSEX icc;
  966. icc.dwSize = sizeof(icc);
  967. icc.dwICC = ICC_BAR_CLASSES;
  968. InitCommonControlsEx(&icc);
  969. return (SLIDESHOW_MODE == m_dwMode) ? _CreateSlideshowToolbar() : _CreateViewerToolbar();
  970. }
  971. static const TBBUTTON c_tbSlideShow[] =
  972. {
  973. // override default toolbar width for separators; iBitmap member of
  974. // TBBUTTON struct is a union of bitmap index & separator width
  975. { 0, ID_PLAYCMD, TBSTATE_ENABLED | TBSTATE_CHECKED, TBSTYLE_CHECKGROUP, {0,0}, 0, 0},
  976. { 1, ID_PAUSECMD, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, {0,0}, 0, 0},
  977. { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, 0},
  978. { 2, ID_PREVCMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, 0},
  979. { 3, ID_NEXTCMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, 0},
  980. #if 0
  981. { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, 0},
  982. { 5, ID_DELETECMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, 0},
  983. #endif
  984. { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, 0},
  985. { 4, ID_CLOSECMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, 0},
  986. };
  987. BOOL CPreviewWnd::_CreateSlideshowToolbar()
  988. {
  989. DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
  990. CCS_NODIVIDER | CCS_NORESIZE |
  991. TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS;
  992. HWND hwndTB = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL, dwStyle, 0, 0, 0, 0,
  993. m_hWnd, NULL, _Module.GetModuleInstance(), NULL);
  994. _InitializeToolbar(hwndTB, IDB_SLIDESHOWTOOLBAR, IDB_SLIDESHOWTOOLBAR_HOT, IDB_SLIDESHOWTOOLBARHIGH, IDB_SLIDESHOWTOOLBARHIGH_HOT);
  995. TBBUTTON tbSlideShow[ARRAYSIZE(c_tbSlideShow)];
  996. memcpy(tbSlideShow, c_tbSlideShow, sizeof(c_tbSlideShow));
  997. // Add the buttons, and then set the minimum and maximum button widths.
  998. ::SendMessage(hwndTB, TB_ADDBUTTONS, (UINT)ARRAYSIZE(c_tbSlideShow), (LPARAM)tbSlideShow);
  999. LRESULT dwSize = ::SendMessage(hwndTB, TB_GETBUTTONSIZE, 0, 0);
  1000. SIZE size = {0, HIWORD(dwSize)};
  1001. ::SendMessage(hwndTB, TB_GETIDEALSIZE, 0, (LPARAM)&size);
  1002. RECT rcClient;
  1003. RECT rcToolbar = {0, 0, size.cx, size.cy};
  1004. GetClientRect(&rcClient);
  1005. AdjustWindowRectEx(&rcToolbar, dwStyle, FALSE, WS_EX_TOOLWINDOW);
  1006. ::SetWindowPos(hwndTB, HWND_TOP, RECTWIDTH(rcClient)-RECTWIDTH(rcToolbar), 0,
  1007. RECTWIDTH(rcToolbar), RECTHEIGHT(rcToolbar), 0);
  1008. //> REVIEW This is a feature that CyraR would like to get into Whistler, but it doesn't seem to work. I will investigate more after Beta1
  1009. // LONG lStyle = ::GetWindowLong(hwndTB, GWL_EXSTYLE);
  1010. // ::SetWindowLong(hwndTB, GWL_EXSTYLE, lStyle | WS_EX_LAYERED);
  1011. // if (::SetLayeredWindowAttributes(hwndTB, 0, 0, 0) == 0)
  1012. // {
  1013. // void *lpMsgBuf;
  1014. // ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  1015. // NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
  1016. //
  1017. // MessageBox((LPCTSTR)lpMsgBuf, L"Error", MB_OK | MB_ICONINFORMATION);
  1018. // ::LocalFree(lpMsgBuf);
  1019. // }
  1020. m_ctlToolbar.SubclassWindow(hwndTB);
  1021. ShowSSToolbar(FALSE, TRUE);
  1022. return (NULL != hwndTB);
  1023. }
  1024. enum EViewerToolbarButtons
  1025. {
  1026. PREVIMGPOS = 0,
  1027. NEXTIMGPOS,
  1028. VIEWSEPPOS, // seperator
  1029. BESTFITPOS,
  1030. ACTUALSIZEPOS,
  1031. SLIDESHOWPOS,
  1032. IMAGECMDSEPPOS, // seperator
  1033. ZOOMINPOS,
  1034. ZOOMEOUTPOS,
  1035. SELECTPOS,
  1036. CROPPOS,
  1037. ROTATESEPPOS, // seperator
  1038. ROTATE90POS,
  1039. ROTATE270POS,
  1040. // these are all TIFF related
  1041. PAGESEPPOS,
  1042. PREVPAGEPOS,
  1043. PAGELISTPOS,
  1044. NEXTPAGEPOS,
  1045. ANNOTATEPOS,
  1046. FREEHANDPOS,
  1047. HIGLIGHTPOS,
  1048. LINEPOS,
  1049. FRAMEPOS,
  1050. RECTPOS,
  1051. TEXTPOS,
  1052. NOTEPOS,
  1053. PRINTSEPPOS,
  1054. DELETEPOS,
  1055. PRINTPOS,
  1056. PROPERTIESPOS,
  1057. SAVEASPOS,
  1058. OPENPOS,
  1059. HELPSEPPOS,
  1060. HELPPOS,
  1061. MAXPOS,
  1062. };
  1063. static const TBBUTTON c_tbViewer[] =
  1064. {
  1065. // override default toolbar width for separators; iBitmap member of
  1066. // TBBUTTON struct is a union of bitmap index & separator width
  1067. { 0, ID_PREVIMGCMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1068. { 1, ID_NEXTIMGCMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1069. { 0, ID_VIEWCMDSEP, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1},
  1070. { 5, ID_BESTFITCMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1071. { 6, ID_ACTUALSIZECMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1072. { 8, ID_SLIDESHOWCMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1073. { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1},
  1074. { 2, ID_ZOOMINCMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1075. { 3, ID_ZOOMOUTCMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1076. { 4, ID_SELECTCMD, TBSTATE_HIDDEN, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1077. { 23, ID_CROPCMD, TBSTATE_HIDDEN, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1078. { 0, ID_ROTATESEP, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1},
  1079. { 12, ID_ROTATE90CMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1080. { 11, ID_ROTATE270CMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1081. { 0, ID_PAGECMDSEP, TBSTATE_HIDDEN, TBSTYLE_SEP, {0,0}, 0, -1}, //tiff
  1082. { 9, ID_PREVPAGECMD, TBSTATE_HIDDEN, TBSTYLE_BUTTON, {0,0}, 0, -1}, //tiff
  1083. { I_IMAGENONE, ID_PAGELIST, TBSTATE_HIDDEN, BTNS_WHOLEDROPDOWN | BTNS_SHOWTEXT | BTNS_AUTOSIZE, {0,0}, 0, -1},//tiff
  1084. { 10, ID_NEXTPAGECMD, TBSTATE_HIDDEN, TBSTYLE_BUTTON, {0,0}, 0, -1}, //tiff
  1085. { 0, ID_ANNOTATESEP, TBSTATE_HIDDEN, TBSTYLE_SEP, {0,0}, 0, -1}, //tiff
  1086. { 13, ID_FREEHANDCMD, TBSTATE_HIDDEN, TBSTYLE_BUTTON, {0,0}, 0, -1}, //tiff
  1087. { 14, ID_HIGHLIGHTCMD, TBSTATE_HIDDEN, TBSTYLE_BUTTON, {0,0}, 0, -1}, //tiff
  1088. { 15, ID_LINECMD, TBSTATE_HIDDEN, TBSTYLE_BUTTON, {0,0}, 0, -1}, //tiff
  1089. { 16, ID_FRAMECMD, TBSTATE_HIDDEN, TBSTYLE_BUTTON, {0,0}, 0, -1}, //tiff
  1090. { 17, ID_RECTCMD, TBSTATE_HIDDEN, TBSTYLE_BUTTON, {0,0}, 0, -1}, //tiff
  1091. { 18, ID_TEXTCMD, TBSTATE_HIDDEN, TBSTYLE_BUTTON, {0,0}, 0, -1}, //tiff
  1092. { 19, ID_NOTECMD, TBSTATE_HIDDEN, TBSTYLE_BUTTON, {0,0}, 0, -1}, //tiff
  1093. { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1},
  1094. { 25, ID_DELETECMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1095. { 20, ID_PRINTCMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1096. { 21, ID_PROPERTIESCMD, TBSTATE_HIDDEN, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1097. { 22, ID_SAVEASCMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1098. { 26, ID_OPENCMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1099. { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1},
  1100. { 24, ID_HELPCMD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  1101. };
  1102. void CPreviewWnd::_InitializeViewerToolbarButtons(HWND hwndToolbar, const TBBUTTON c_tbbuttons[], size_t c_nButtons, TBBUTTON tbbuttons[], size_t nButtons)
  1103. {
  1104. ASSERT(c_nButtons == nButtons); // Sanity check.
  1105. ASSERT(c_nButtons <= 100); // Sanity check.
  1106. // Determine if running RTL mirrored and initialize toolbar accordingly.
  1107. if (!m_bRTLMirrored)
  1108. {
  1109. //
  1110. // Init LTR.
  1111. //
  1112. memcpy(tbbuttons, c_tbbuttons, c_nButtons * sizeof(TBBUTTON));
  1113. }
  1114. else
  1115. {
  1116. //
  1117. // Init RTL.
  1118. //
  1119. // Toolbar window inherits RTL style from parent hwnd, but we don't
  1120. // want full-blown RTL. We do want the icons to have their positions
  1121. // reversed in the toolbar, but we don't want the button bitmaps to
  1122. // get blitted backwards. So we turn of RTL for the toolbar hwnd
  1123. // and do a manual reorder of the buttons in RTL fashion.
  1124. // Remove RTL style from toolbar hwnd.
  1125. DWORD dwStyle = ::GetWindowLong(hwndToolbar, GWL_EXSTYLE);
  1126. DWORD dwNewStyle = (dwStyle & ~WS_EX_LAYOUTRTL);
  1127. ASSERT(dwStyle != dwNewStyle); // Sanity check.
  1128. ::SetWindowLong(hwndToolbar, GWL_EXSTYLE, dwNewStyle);
  1129. // Reverse toolbar button order.
  1130. size_t iFrom = nButtons - 1;
  1131. size_t iTo = 0;
  1132. while (iTo < iFrom)
  1133. {
  1134. memcpy(&tbbuttons[iTo], &c_tbbuttons[iFrom], sizeof(TBBUTTON));
  1135. memcpy(&tbbuttons[iFrom], &c_tbbuttons[iTo], sizeof(TBBUTTON));
  1136. iFrom--;
  1137. iTo++;
  1138. }
  1139. if (iTo == iFrom)
  1140. {
  1141. memcpy(&tbbuttons[iTo], &c_tbbuttons[iFrom], sizeof(TBBUTTON));
  1142. }
  1143. }
  1144. }
  1145. inline UINT CPreviewWnd::_IndexOfViewerToolbarButton(EViewerToolbarButtons eButton)
  1146. {
  1147. ASSERT(eButton > 0);
  1148. if (!m_bRTLMirrored)
  1149. {
  1150. return eButton;
  1151. }
  1152. else
  1153. {
  1154. return MAXPOS - eButton - 1;
  1155. }
  1156. }
  1157. BOOL CPreviewWnd::_CreateViewerToolbar()
  1158. {
  1159. DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
  1160. CCS_NODIVIDER | CCS_NORESIZE |
  1161. TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS;
  1162. HWND hwndTB = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, dwStyle, 0, 0, 0, 0,
  1163. m_hWnd, NULL, _Module.GetModuleInstance(), NULL);
  1164. _InitializeToolbar(hwndTB, IDB_TOOLBAR, IDB_TOOLBAR_HOT, IDB_TOOLBARHIGH, IDB_TOOLBARHIGH_HOT);
  1165. TBBUTTON tbbuttons[ARRAYSIZE(c_tbViewer)];
  1166. _InitializeViewerToolbarButtons(hwndTB, c_tbViewer, ARRAYSIZE(c_tbViewer), tbbuttons, ARRAYSIZE(tbbuttons));
  1167. if (CONTROL_MODE == m_dwMode)
  1168. {
  1169. ASSERT(ID_BESTFITCMD==tbbuttons[_IndexOfViewerToolbarButton(BESTFITPOS)].idCommand);
  1170. tbbuttons[_IndexOfViewerToolbarButton(BESTFITPOS)].fsState = TBSTATE_HIDDEN;
  1171. ASSERT(ID_ACTUALSIZECMD==tbbuttons[_IndexOfViewerToolbarButton(ACTUALSIZEPOS)].idCommand);
  1172. tbbuttons[_IndexOfViewerToolbarButton(ACTUALSIZEPOS)].fsState = TBSTATE_HIDDEN;
  1173. ASSERT(ID_SLIDESHOWCMD==tbbuttons[_IndexOfViewerToolbarButton(SLIDESHOWPOS)].idCommand);
  1174. tbbuttons[_IndexOfViewerToolbarButton(SLIDESHOWPOS)].fsState = TBSTATE_HIDDEN;
  1175. ASSERT(ID_ZOOMINCMD==tbbuttons[_IndexOfViewerToolbarButton(ZOOMINPOS)].idCommand);
  1176. tbbuttons[_IndexOfViewerToolbarButton(ZOOMINPOS)].fsState = TBSTATE_HIDDEN;
  1177. ASSERT(ID_ZOOMOUTCMD==tbbuttons[_IndexOfViewerToolbarButton(ZOOMEOUTPOS)].idCommand);
  1178. tbbuttons[_IndexOfViewerToolbarButton(ZOOMEOUTPOS)].fsState = TBSTATE_HIDDEN;
  1179. ASSERT(ID_SAVEASCMD==tbbuttons[_IndexOfViewerToolbarButton(SAVEASPOS)].idCommand);
  1180. tbbuttons[_IndexOfViewerToolbarButton(SAVEASPOS)].fsState = TBSTATE_HIDDEN;
  1181. ASSERT(ID_DELETECMD==tbbuttons[_IndexOfViewerToolbarButton(DELETEPOS)].idCommand);
  1182. tbbuttons[_IndexOfViewerToolbarButton(DELETEPOS)].fsState = TBSTATE_HIDDEN;
  1183. ASSERT(ID_OPENCMD==tbbuttons[_IndexOfViewerToolbarButton(OPENPOS)].idCommand);
  1184. tbbuttons[_IndexOfViewerToolbarButton(OPENPOS)].fsState = TBSTATE_HIDDEN;
  1185. ASSERT(ID_HELPCMD==tbbuttons[_IndexOfViewerToolbarButton(HELPPOS)].idCommand);
  1186. tbbuttons[_IndexOfViewerToolbarButton(HELPPOS)].fsState = TBSTATE_HIDDEN;
  1187. // remove a few seperators too:
  1188. tbbuttons[_IndexOfViewerToolbarButton(VIEWSEPPOS)].fsState = TBSTATE_HIDDEN;
  1189. tbbuttons[_IndexOfViewerToolbarButton(IMAGECMDSEPPOS)].fsState = TBSTATE_HIDDEN;
  1190. tbbuttons[_IndexOfViewerToolbarButton(PRINTSEPPOS)].fsState = TBSTATE_HIDDEN;
  1191. tbbuttons[_IndexOfViewerToolbarButton(HELPSEPPOS)].fsState = TBSTATE_HIDDEN;
  1192. }
  1193. if (m_fHidePrintBtn)
  1194. {
  1195. ASSERT(ID_PRINTCMD==tbbuttons[_IndexOfViewerToolbarButton(PRINTPOS)].idCommand);
  1196. tbbuttons[_IndexOfViewerToolbarButton(PRINTPOS)].fsState = TBSTATE_HIDDEN;
  1197. }
  1198. if (m_fDisableEdit)
  1199. {
  1200. ASSERT(ID_ROTATESEP == tbbuttons[_IndexOfViewerToolbarButton(ROTATESEPPOS)].idCommand);
  1201. tbbuttons[_IndexOfViewerToolbarButton(ROTATESEPPOS)].fsState = TBSTATE_HIDDEN;
  1202. ASSERT(ID_ROTATE90CMD == tbbuttons[_IndexOfViewerToolbarButton(ROTATE90POS)].idCommand);
  1203. tbbuttons[_IndexOfViewerToolbarButton(ROTATE90POS)].fsState = TBSTATE_HIDDEN;
  1204. ASSERT(ID_ROTATE270CMD == tbbuttons[_IndexOfViewerToolbarButton(ROTATE270POS)].idCommand);
  1205. tbbuttons[_IndexOfViewerToolbarButton(ROTATE270POS)].fsState = TBSTATE_HIDDEN;
  1206. }
  1207. if (m_bRTLMirrored)
  1208. {
  1209. UINT uTmp = tbbuttons[_IndexOfViewerToolbarButton(PREVIMGPOS)].iBitmap;
  1210. tbbuttons[_IndexOfViewerToolbarButton(PREVIMGPOS)].iBitmap = tbbuttons[_IndexOfViewerToolbarButton(NEXTIMGPOS)].iBitmap;
  1211. tbbuttons[_IndexOfViewerToolbarButton(NEXTIMGPOS)].iBitmap = uTmp;
  1212. uTmp = tbbuttons[_IndexOfViewerToolbarButton(PREVPAGEPOS)].iBitmap;
  1213. tbbuttons[_IndexOfViewerToolbarButton(PREVPAGEPOS)].iBitmap = tbbuttons[_IndexOfViewerToolbarButton(NEXTPAGEPOS)].iBitmap;
  1214. tbbuttons[_IndexOfViewerToolbarButton(NEXTPAGEPOS)].iBitmap = uTmp;
  1215. }
  1216. // Add the buttons, and then set the minimum and maximum button widths.
  1217. ::SendMessage(hwndTB, TB_ADDBUTTONS, ARRAYSIZE(tbbuttons), (LPARAM)tbbuttons);
  1218. // we just created the toolbar so we are now in the hidden state of the multipage buttons.
  1219. m_dwMultiPageMode = MPCMD_HIDDEN;
  1220. m_fCanAnnotate = FALSE;
  1221. m_fCanCrop = FALSE;
  1222. m_ctlToolbar.SubclassWindow(hwndTB);
  1223. return (NULL != hwndTB);
  1224. }
  1225. void CPreviewWnd::_InitializeToolbar(HWND hwndTB, int idLow, int idLowHot, int idHigh, int idHighHot)
  1226. {
  1227. int cxBitmap = 16, cyBitmap = 16;
  1228. ::SendMessage(hwndTB, CCM_SETVERSION, COMCTL32_VERSION, 0);
  1229. ::SendMessage (hwndTB, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_HIDECLIPPEDBUTTONS | TBSTYLE_EX_MIXEDBUTTONS | TBSTYLE_EX_DOUBLEBUFFER);
  1230. // Sets the size of the TBBUTTON structure.
  1231. ::SendMessage(hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
  1232. // Set the maximum number of text rows and bitmap size.
  1233. ::SendMessage(hwndTB, TB_SETMAXTEXTROWS, 1, 0);
  1234. int nDepth = SHGetCurColorRes();
  1235. HIMAGELIST himl = ImageList_LoadImage(_Module.GetModuleInstance(),
  1236. (nDepth > 8) ? MAKEINTRESOURCE(idHigh) : MAKEINTRESOURCE(idLow),
  1237. cxBitmap, 0, RGB(0, 255, 0), IMAGE_BITMAP,
  1238. (nDepth > 8) ? LR_CREATEDIBSECTION : LR_DEFAULTCOLOR);
  1239. ::SendMessage(hwndTB, TB_SETIMAGELIST, 0, (LPARAM)himl);
  1240. HIMAGELIST himlHot = ImageList_LoadImage(_Module.GetModuleInstance(),
  1241. (nDepth > 8) ? MAKEINTRESOURCE(idHighHot) : MAKEINTRESOURCE(idLowHot),
  1242. cxBitmap, 0, RGB(0, 255, 0), IMAGE_BITMAP,
  1243. (nDepth > 8) ? LR_CREATEDIBSECTION : LR_DEFAULTCOLOR);
  1244. ::SendMessage(hwndTB, TB_SETHOTIMAGELIST, 0, (LPARAM)himlHot);
  1245. }
  1246. LRESULT CPreviewWnd::OnPrintClient(UINT , WPARAM wParam, LPARAM lParam, BOOL&)
  1247. {
  1248. COLORREF bgClr = m_ctlPreview.GetBackgroundColor();
  1249. RECT rcFill;
  1250. GetClientRect(&rcFill);
  1251. SHFillRectClr((HDC)wParam, &rcFill, bgClr);
  1252. return TRUE;
  1253. }
  1254. LRESULT CPreviewWnd::OnNeedText(int , LPNMHDR pnmh, BOOL&)
  1255. {
  1256. TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pnmh;
  1257. // tooltip text messages have the same string ID as the control ID
  1258. pTTT->lpszText = MAKEINTRESOURCE(pTTT->hdr.idFrom);
  1259. pTTT->hinst = _Module.GetModuleInstance();
  1260. // Except in Control Mode due to a DUI Web View bug that's too hard to fix for Whistler...
  1261. if (CONTROL_MODE == m_dwMode)
  1262. {
  1263. // keyboard accelerators are broken, so swap IDs around for the few that display them
  1264. static const struct {
  1265. UINT idCommand;
  1266. UINT idsNewName;
  1267. } map[] = {
  1268. { ID_PRINTCMD, IDS_PRINTCMD },
  1269. { ID_ROTATE90CMD, IDS_ROTATE90CMD },
  1270. { ID_ROTATE270CMD, IDS_ROTATE270CMD }};
  1271. for (int i = 0 ; i < ARRAYSIZE(map) ; i++)
  1272. {
  1273. if (map[i].idCommand == pTTT->hdr.idFrom)
  1274. {
  1275. pTTT->lpszText = MAKEINTRESOURCE(map[i].idsNewName);
  1276. break;
  1277. }
  1278. }
  1279. }
  1280. return TRUE;
  1281. }
  1282. LRESULT CPreviewWnd::OnDropDown(int id, LPNMHDR pnmh, BOOL&)
  1283. {
  1284. LPNMTOOLBAR pnmTB = (LPNMTOOLBAR)pnmh;
  1285. switch (pnmTB->iItem)
  1286. {
  1287. case ID_PAGELIST:
  1288. _DropDownPageList (pnmTB);
  1289. break;
  1290. default:
  1291. return TRUE;
  1292. }
  1293. return FALSE;
  1294. }
  1295. void CPreviewWnd::_DropDownPageList(LPNMTOOLBAR pnmTB)
  1296. {
  1297. HMENU hmenuPopup = CreatePopupMenu();
  1298. if (hmenuPopup)
  1299. {
  1300. for (DWORD i = 1; i <= m_pImageData->_cImages; i++)
  1301. {
  1302. TCHAR szBuffer[10];
  1303. wsprintf(szBuffer, TEXT("%d"), i);
  1304. MENUITEMINFO mii = {0};
  1305. mii.cbSize = sizeof(mii);
  1306. mii.fMask = MIIM_STRING | MIIM_ID;
  1307. mii.wID = i;
  1308. mii.dwTypeData = szBuffer;
  1309. InsertMenuItem (hmenuPopup, i-1, TRUE, &mii);
  1310. }
  1311. RECT rc;
  1312. ::SendMessage(pnmTB->hdr.hwndFrom, TB_GETRECT, (WPARAM)pnmTB->iItem, (LPARAM)&rc);
  1313. ::MapWindowPoints(pnmTB->hdr.hwndFrom, HWND_DESKTOP, (LPPOINT)&rc, 2);
  1314. TPMPARAMS tpm = { 0};
  1315. tpm.cbSize = sizeof(TPMPARAMS);
  1316. tpm.rcExclude = rc;
  1317. BOOL bRet = ::TrackPopupMenuEx(hmenuPopup,
  1318. TPM_RETURNCMD | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL | TPM_NONOTIFY,
  1319. rc.left, rc.bottom,
  1320. m_hWnd, &tpm);
  1321. if (bRet)
  1322. {
  1323. if (m_fDirty)
  1324. {
  1325. m_ctlPreview.CommitAnnotations();
  1326. }
  1327. m_pImageData->SelectPage((LONG)bRet-1);
  1328. _UpdateImage();
  1329. _SetMultipageCommands();
  1330. }
  1331. DestroyMenu(hmenuPopup);
  1332. }
  1333. }
  1334. void CPreviewWnd::SetNotify(CEvents * pEvents)
  1335. {
  1336. m_pEvents = pEvents;
  1337. }
  1338. void CPreviewWnd::SetPalette(HPALETTE hpal)
  1339. {
  1340. m_hpal = hpal;
  1341. }
  1342. BOOL CPreviewWnd::GetPrintable()
  1343. {
  1344. return m_fPrintable;
  1345. }
  1346. LRESULT CPreviewWnd::OnWheelTurn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&)
  1347. {
  1348. // REVIEW: Shouldn't this just be translated into a command?
  1349. // this message is ALWAYS forwarded to the zoom window
  1350. m_ctlPreview.SendMessage(uMsg, wParam, lParam);
  1351. // Since we know that the mouse wheel will either ZoomIn or ZoomOut lets update the buttons if we are in Window Mode.
  1352. if (WINDOW_MODE == m_dwMode)
  1353. {
  1354. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_ACTUALSIZECMD, MAKELONG(TRUE, 0));
  1355. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_BESTFITCMD, MAKELONG(!m_ctlPreview.IsBestFit(), 0));
  1356. }
  1357. return 0;
  1358. }
  1359. BOOL CPreviewWnd::OnNonSlideShowTab()
  1360. {
  1361. BOOL fHandled = FALSE;
  1362. if ((SLIDESHOW_MODE != m_dwMode) && m_fShowToolbar)
  1363. {
  1364. if (GetFocus() != m_ctlToolbar.m_hWnd)
  1365. {
  1366. m_ctlToolbar.SetFocus();
  1367. m_ctlToolbar.SetActiveWindow();
  1368. m_ctlToolbar.SendMessage(TB_SETHOTITEM, 0, 0);
  1369. m_iSSToolbarSelect = 0;
  1370. fHandled = TRUE;
  1371. }
  1372. }
  1373. return fHandled;
  1374. }
  1375. // Forwards WM_KEYUP and WM_KEYDOWN events to the zoom window but only if they are keys
  1376. // that the zoom window cares about.
  1377. // Activates the slideshow toolbar if needed
  1378. LRESULT CPreviewWnd::OnKeyEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled)
  1379. {
  1380. MSG msg;
  1381. msg.hwnd = m_hWnd;
  1382. msg.message = uMsg;
  1383. msg.wParam = wParam;
  1384. msg.lParam = lParam;
  1385. GetCursorPos (&msg.pt);
  1386. fHandled = FALSE;
  1387. if (SLIDESHOW_MODE == m_dwMode)
  1388. {
  1389. if (WM_KEYDOWN == uMsg)
  1390. {
  1391. switch (wParam)
  1392. {
  1393. case VK_TAB:
  1394. OnSlideshowCommand(0, ID_PAUSECMD, NULL, fHandled);
  1395. ShowSSToolbar(TRUE);
  1396. KillTimer(TIMER_TOOLBAR);
  1397. m_ctlToolbar.SetFocus();
  1398. m_ctlToolbar.SendMessage(TB_SETHOTITEM, 0, 0);
  1399. m_iSSToolbarSelect = 0;
  1400. fHandled = TRUE;
  1401. break;
  1402. case VK_SPACE:
  1403. ShowSSToolbar(!m_fPaused); // if we are unpausing, hide the toolbar if it's shown. if we are pausing, show the toolbar
  1404. OnSlideshowCommand(0, m_fPaused ? ID_PLAYCMD : ID_PAUSECMD, NULL, fHandled);
  1405. break;
  1406. case VK_PRIOR: // PAGEUP
  1407. case VK_UP:
  1408. case VK_LEFT:
  1409. case VK_BACK: // BACKSPACE
  1410. OnSlideshowCommand(0, ID_PREVCMD, NULL, fHandled);
  1411. break;
  1412. case VK_NEXT: // PAGEDOWN
  1413. case VK_RIGHT:
  1414. case VK_DOWN:
  1415. case VK_RETURN: // ENTER
  1416. OnSlideshowCommand(0, ID_NEXTCMD, NULL, fHandled);
  1417. break;
  1418. case VK_DELETE:
  1419. _DeleteCurrentSlide();
  1420. fHandled = TRUE;
  1421. break;
  1422. case 'K':
  1423. if (0x8000 & GetKeyState(VK_CONTROL))
  1424. {
  1425. OnSlideshowCommand(0, ID_PAUSECMD, NULL, fHandled);
  1426. Rotate(90);
  1427. fHandled = TRUE;
  1428. }
  1429. break;
  1430. case 'L':
  1431. if (0x8000 & GetKeyState(VK_CONTROL))
  1432. {
  1433. OnSlideshowCommand(0, ID_PAUSECMD, NULL, fHandled);
  1434. Rotate(270);
  1435. fHandled = TRUE;
  1436. }
  1437. break;
  1438. case VK_ESCAPE:
  1439. PostMessage(m_fExitApp ? WM_QUIT : WM_CLOSE, 0, 0);
  1440. fHandled = TRUE;
  1441. break;
  1442. }
  1443. }
  1444. }
  1445. else if (!TranslateAccelerator(&msg)) // Only translate accelerators in the non-slideshow case
  1446. // Slideshow keys are handled explicitly above
  1447. {
  1448. switch (wParam)
  1449. {
  1450. case VK_SHIFT:
  1451. case VK_CONTROL:
  1452. case VK_PRIOR:
  1453. case VK_NEXT:
  1454. case VK_HOME:
  1455. case VK_END:
  1456. // these are forwarded to the zoom window
  1457. m_ctlPreview.SendMessage(uMsg, wParam, lParam);
  1458. break;
  1459. case VK_TAB:
  1460. fHandled = OnNonSlideShowTab();
  1461. break;
  1462. case VK_ESCAPE:
  1463. m_ctlPreview.SetMode(CZoomWnd::MODE_NOACTION);
  1464. _UpdateButtons(NOBUTTON);
  1465. fHandled = TRUE;
  1466. break;
  1467. }
  1468. }
  1469. return 0;
  1470. }
  1471. // OnTBKeyEvent
  1472. //
  1473. LRESULT CPreviewWnd::OnTBKeyEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled)
  1474. {
  1475. fHandled = FALSE;
  1476. if (SLIDESHOW_MODE == m_dwMode && m_fToolbarHidden)
  1477. {
  1478. ShowSSToolbar(TRUE);
  1479. m_ctlToolbar.SetFocus();
  1480. m_ctlToolbar.SendMessage(TB_SETHOTITEM, 0, 0);
  1481. m_iSSToolbarSelect = 0;
  1482. fHandled = TRUE;
  1483. }
  1484. else
  1485. {
  1486. switch (wParam)
  1487. {
  1488. case VK_ESCAPE:
  1489. if (WM_KEYDOWN == uMsg)
  1490. {
  1491. if (SLIDESHOW_MODE == m_dwMode)
  1492. {
  1493. PostMessage(m_fExitApp ? WM_QUIT : WM_CLOSE, 0, 0);
  1494. }
  1495. else
  1496. {
  1497. m_ctlPreview.SetMode(CZoomWnd::MODE_NOACTION);
  1498. _UpdateButtons(NOBUTTON);
  1499. SetFocus();
  1500. SetActiveWindow();
  1501. }
  1502. }
  1503. break;
  1504. case VK_SHIFT:
  1505. case VK_CONTROL:
  1506. case VK_PRIOR:
  1507. case VK_NEXT:
  1508. case VK_HOME:
  1509. case VK_END:
  1510. // these are forwarded to the zoom window
  1511. m_ctlPreview.SendMessage(uMsg, wParam, lParam);
  1512. break;
  1513. case VK_LEFT:
  1514. case VK_RIGHT:
  1515. if (WM_KEYDOWN == uMsg)
  1516. {
  1517. int iSel = (int)m_ctlToolbar.SendMessage(TB_GETHOTITEM, 0, 0);
  1518. int iSize = (int)m_ctlToolbar.SendMessage(TB_BUTTONCOUNT, 0, 0);
  1519. int iStepSize = (wParam == VK_RIGHT) ? 1 : iSize - 1; // ((pos + (size - 1)) % size) == left by 1
  1520. if (iSel != -1)
  1521. {
  1522. m_iSSToolbarSelect = iSel;
  1523. }
  1524. TBBUTTON tb = {0};
  1525. do
  1526. {
  1527. m_iSSToolbarSelect = (m_iSSToolbarSelect + iStepSize) % iSize;
  1528. m_ctlToolbar.SendMessage(TB_GETBUTTON, m_iSSToolbarSelect, (LPARAM)&tb);
  1529. }
  1530. while ((tb.fsStyle & TBSTYLE_SEP) || (tb.fsState & TBSTATE_HIDDEN) || !(tb.fsState & TBSTATE_ENABLED)); // don't stop on the separators
  1531. m_ctlToolbar.SendMessage(TB_SETHOTITEM, m_iSSToolbarSelect, 0);
  1532. fHandled = TRUE;
  1533. }
  1534. break;
  1535. case VK_RETURN:
  1536. case VK_SPACE:
  1537. if ((WM_KEYDOWN == uMsg) && (SLIDESHOW_MODE == m_dwMode))
  1538. {
  1539. // to "press" the button, get its command id and sendmessage on it
  1540. // TB_PRESSBUTTON doesn't work here, don't know why.
  1541. // m_ctlToolbar.SendMessage(TB_PRESSBUTTON, m_iSSToolbarSelect, MAKELONG(TRUE, 0));
  1542. TBBUTTON tbbutton;
  1543. if (m_ctlToolbar.SendMessage(TB_GETBUTTON, m_iSSToolbarSelect, (LPARAM)&tbbutton))
  1544. {
  1545. OnSlideshowCommand(0, (WORD)tbbutton.idCommand, NULL, fHandled);
  1546. }
  1547. fHandled = TRUE;
  1548. }
  1549. break;
  1550. case VK_TAB:
  1551. if ((WM_KEYDOWN == uMsg) && (CONTROL_MODE != m_dwMode))
  1552. {
  1553. // move focus back to the previewwnd
  1554. SetFocus();
  1555. fHandled = TRUE;
  1556. ShowSSToolbar(FALSE);
  1557. SetTimer(TIMER_TOOLBAR, m_uTimeout);
  1558. }
  1559. break;
  1560. default:
  1561. break;
  1562. }
  1563. }
  1564. return 0;
  1565. }
  1566. LRESULT CPreviewWnd::OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled)
  1567. {
  1568. fHandled = FALSE;
  1569. if ((SLIDESHOW_MODE == m_dwMode) &&
  1570. ((SC_MONITORPOWER == wParam) || (SC_SCREENSAVE == wParam)))
  1571. {
  1572. fHandled = TRUE;
  1573. }
  1574. return 0;
  1575. }
  1576. HRESULT CPreviewWnd::_PreviewFromStream(IStream *pStream, UINT iItem, BOOL fUpdateCaption)
  1577. {
  1578. IRunnableTask * pTask;
  1579. if (fUpdateCaption)
  1580. {
  1581. // set the caption here in case decode fails
  1582. STATSTG stat;
  1583. if (SUCCEEDED(pStream->Stat(&stat, 0)))
  1584. {
  1585. SetCaptionInfo(stat.pwcsName);
  1586. CoTaskMemFree(stat.pwcsName);
  1587. }
  1588. else
  1589. {
  1590. SetCaptionInfo(NULL);
  1591. }
  1592. }
  1593. HRESULT hr = CDecodeTask::Create(pStream, NULL, iItem, m_pImageFactory, m_hWnd, &pTask);
  1594. if (SUCCEEDED(hr))
  1595. {
  1596. TASKOWNERID toid;
  1597. GetTaskIDFromMode(GTIDFM_DECODE, m_dwMode, &toid);
  1598. hr = m_pTaskScheduler->AddTask(pTask, toid, 0, ITSAT_DEFAULT_PRIORITY);
  1599. pTask->Release();
  1600. }
  1601. return hr;
  1602. }
  1603. HRESULT CPreviewWnd::_PreviewFromFile(LPCTSTR pszFile, UINT iItem, BOOL fUpdateCaption)
  1604. {
  1605. IRunnableTask * pTask;
  1606. if (fUpdateCaption)
  1607. {
  1608. // set the caption here in case decode fails
  1609. SetCaptionInfo(pszFile);
  1610. }
  1611. HRESULT hr = CDecodeTask::Create(NULL, pszFile, iItem, m_pImageFactory, m_hWnd, &pTask);
  1612. if (SUCCEEDED(hr))
  1613. {
  1614. TASKOWNERID toid;
  1615. GetTaskIDFromMode(GTIDFM_DECODE, m_dwMode, &toid);
  1616. hr = m_pTaskScheduler->AddTask(pTask, toid, 0, ITSAT_DEFAULT_PRIORITY);
  1617. pTask->Release();
  1618. }
  1619. return hr;
  1620. }
  1621. #define SLIDESHOW_CURSOR_NOTBUSY 0x0
  1622. #define SLIDESHOW_CURSOR_BUSY 0x1
  1623. #define SLIDESHOW_CURSOR_HIDDEN 0x2
  1624. #define SLIDESHOW_CURSOR_NORMAL 0x3
  1625. #define SLIDESHOW_CURSOR_CURRENT 0x4
  1626. void CPreviewWnd::SetCursorState(DWORD dwType)
  1627. {
  1628. switch (dwType)
  1629. {
  1630. case SLIDESHOW_CURSOR_NOTBUSY:
  1631. KillTimer(TIMER_BUSYCURSOR);
  1632. if (m_fBusy) // ignore multiple NOTBUSY, which we receive for the precaching
  1633. {
  1634. m_hCurrent = m_hCurOld;
  1635. SetCursor(m_hCurrent);
  1636. m_fBusy = FALSE;
  1637. }
  1638. break;
  1639. case SLIDESHOW_CURSOR_BUSY:
  1640. if (!m_fBusy)
  1641. {
  1642. m_hCurrent = LoadCursor(NULL, IDC_APPSTARTING);
  1643. m_hCurOld = SetCursor(m_hCurrent);
  1644. m_fBusy = TRUE;
  1645. }
  1646. break;
  1647. case SLIDESHOW_CURSOR_HIDDEN:
  1648. m_hCurOld = NULL;
  1649. if (!m_fBusy)
  1650. {
  1651. m_hCurrent = m_hCurOld;
  1652. SetCursor(m_hCurrent);
  1653. }
  1654. break;
  1655. case SLIDESHOW_CURSOR_NORMAL:
  1656. m_hCurOld = LoadCursor(NULL, IDC_ARROW);
  1657. if (!m_fBusy)
  1658. {
  1659. m_hCurrent = m_hCurOld;
  1660. SetCursor(m_hCurrent);
  1661. }
  1662. break;
  1663. case SLIDESHOW_CURSOR_CURRENT:
  1664. SetCursor(m_hCurrent);
  1665. break;
  1666. }
  1667. }
  1668. LRESULT CPreviewWnd::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled)
  1669. {
  1670. if (TIMER_ANIMATION == wParam)
  1671. {
  1672. KillTimer(TIMER_ANIMATION);
  1673. if (m_pImageData && m_pImageData->IsAnimated() && _ShouldDisplayAnimations()) // might have switched pages between timer calls
  1674. {
  1675. if (m_pImageData->NextFrame())
  1676. {
  1677. SetTimer(TIMER_ANIMATION, m_pImageData->GetDelay());
  1678. // paint the new image
  1679. _UpdateImage();
  1680. }
  1681. }
  1682. }
  1683. else if (TIMER_DATAOBJECT == wParam)
  1684. {
  1685. KillTimer(TIMER_DATAOBJECT); // on shot timer
  1686. if (_pdtobj)
  1687. {
  1688. PreviewItemsFromUnk(_pdtobj);
  1689. ATOMICRELEASE(_pdtobj);
  1690. }
  1691. }
  1692. else if (TIMER_BUSYCURSOR == wParam)
  1693. {
  1694. SetCursorState(SLIDESHOW_CURSOR_BUSY);
  1695. }
  1696. else if (SLIDESHOW_MODE == m_dwMode)
  1697. {
  1698. if (TIMER_SLIDESHOW == wParam)
  1699. {
  1700. _ShowNextSlide(FALSE); // always go forward?
  1701. }
  1702. else if (TIMER_TOOLBAR == wParam && !m_fIgnoreUITimers)
  1703. {
  1704. KillTimer(TIMER_TOOLBAR);
  1705. ShowSSToolbar(FALSE);
  1706. }
  1707. }
  1708. return 0;
  1709. }
  1710. void CPreviewWnd::ShowSSToolbar(BOOL bShow, BOOL fForce /*=FALSE*/)
  1711. {
  1712. if (SLIDESHOW_MODE == m_dwMode)
  1713. {
  1714. if (fForce)
  1715. {
  1716. POINT pt;
  1717. RECT rc;
  1718. GetCursorPos(&pt);
  1719. GetWindowRect(&rc);
  1720. if (PtInRect(&rc, pt))
  1721. {
  1722. g_x = pt.x;
  1723. g_y = pt.y;
  1724. }
  1725. }
  1726. if (!bShow)
  1727. {
  1728. if (!m_fToolbarHidden || fForce)
  1729. {
  1730. //AnimateWindow(m_ctlToolbar.m_hWnd, 200, AW_VER_NEGATIVE | AW_SLIDE | AW_HIDE);
  1731. m_ctlToolbar.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
  1732. m_fToolbarHidden = TRUE;
  1733. m_ctlToolbar.SendMessage(TB_SETHOTITEM, -1, 0);
  1734. SetCursorState(SLIDESHOW_CURSOR_HIDDEN);
  1735. }
  1736. }
  1737. else
  1738. {
  1739. KillTimer(TIMER_TOOLBAR);
  1740. if (m_fToolbarHidden || fForce)
  1741. {
  1742. //AnimateWindow(m_ctlToolbar.m_hWnd, 200, AW_VER_POSITIVE | AW_SLIDE | AW_ACTIVATE);
  1743. m_ctlToolbar.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  1744. m_fToolbarHidden = FALSE;
  1745. SetCursorState(SLIDESHOW_CURSOR_NORMAL);
  1746. }
  1747. SetTimer(TIMER_TOOLBAR, m_uTimeout);
  1748. }
  1749. }
  1750. }
  1751. void CPreviewWnd::OnDraw(HDC hdc)
  1752. {
  1753. if (m_fCropping)
  1754. {
  1755. CSelectionTracker tracker;
  1756. _SetupCroppingTracker(tracker);
  1757. CRect rectImage(0, 0, m_ctlPreview.m_cxImage, m_ctlPreview.m_cyImage);
  1758. m_ctlPreview.GetWindowFromImage((LPPOINT)(LPRECT)rectImage, 2);
  1759. CRect rectCrop = m_rectCropping;
  1760. m_ctlPreview.GetWindowFromImage((LPPOINT)(LPRECT)rectCrop, 2);
  1761. HRGN hrgn = ::CreateRectRgn(0, 0, 0, 0);
  1762. if (hrgn != NULL)
  1763. {
  1764. HRGN hrgnImage = ::CreateRectRgnIndirect(rectImage);
  1765. if (hrgnImage != NULL)
  1766. {
  1767. HRGN hrgnCrop = ::CreateRectRgnIndirect(rectCrop);
  1768. if (hrgnCrop != NULL)
  1769. {
  1770. if (ERROR != ::CombineRgn(hrgn, hrgnImage, hrgnCrop, RGN_DIFF))
  1771. {
  1772. ::InvertRgn(hdc, hrgn);
  1773. }
  1774. ::DeleteObject(hrgnCrop);
  1775. }
  1776. ::DeleteObject(hrgnImage);
  1777. }
  1778. ::DeleteObject(hrgn);
  1779. }
  1780. tracker.Draw(hdc);
  1781. }
  1782. else
  1783. {
  1784. if (m_fAnnotating)
  1785. {
  1786. if (DPA_GetPtrCount(m_hdpaSelectedAnnotations) > 0)
  1787. {
  1788. CSelectionTracker tracker;
  1789. _SetupAnnotatingTracker(tracker);
  1790. tracker.Draw(hdc);
  1791. }
  1792. }
  1793. }
  1794. }
  1795. void CPreviewWnd::OnDrawComplete()
  1796. {
  1797. if (SLIDESHOW_MODE == m_dwMode)
  1798. {
  1799. if (!m_fPaused)
  1800. SetTimer(TIMER_SLIDESHOW, m_uTimeout);
  1801. SetCursorState(SLIDESHOW_CURSOR_NOTBUSY);
  1802. }
  1803. }
  1804. BOOL CPreviewWnd::OnMouseDown(UINT uMsg, WPARAM wParam, LPARAM lParam)
  1805. {
  1806. if (SLIDESHOW_MODE == m_dwMode)
  1807. {
  1808. if (uMsg == WM_LBUTTONDOWN)
  1809. {
  1810. _ShowNextSlide(FALSE); // advance the slide (param is "go back?")
  1811. return TRUE;
  1812. }
  1813. }
  1814. else
  1815. {
  1816. if (m_fCropping)
  1817. return _OnMouseDownForCropping(uMsg, wParam, lParam);
  1818. else
  1819. return _OnMouseDownForAnnotating(uMsg, wParam, lParam);
  1820. }
  1821. return FALSE;
  1822. }
  1823. BOOL CPreviewWnd::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam)
  1824. {
  1825. if (SLIDESHOW_MODE == m_dwMode)
  1826. {
  1827. int xPos = GET_X_LPARAM(lParam);
  1828. int yPos = GET_Y_LPARAM(lParam);
  1829. int dx = xPos > g_x ? xPos - g_x : g_x - xPos;
  1830. int dy = yPos > g_y ? yPos - g_y : g_y - yPos;
  1831. if (dx > 10 || dy > 10)
  1832. {
  1833. ShowSSToolbar(TRUE);
  1834. }
  1835. g_x = xPos;
  1836. g_y = yPos;
  1837. }
  1838. return TRUE;
  1839. }
  1840. LRESULT CPreviewWnd::OnTBMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled)
  1841. {
  1842. if (SLIDESHOW_MODE == m_dwMode)
  1843. {
  1844. m_fTBTrack = FALSE;
  1845. ShowSSToolbar(TRUE);
  1846. }
  1847. fHandled = FALSE;
  1848. return 0;
  1849. }
  1850. LRESULT CPreviewWnd::OnTBMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled)
  1851. {
  1852. if (SLIDESHOW_MODE == m_dwMode)
  1853. {
  1854. if (!m_fTBTrack)
  1855. {
  1856. TRACKMOUSEEVENT tme;
  1857. tme.cbSize = sizeof(tme);
  1858. tme.dwFlags = TME_LEAVE;
  1859. tme.hwndTrack = m_ctlToolbar.m_hWnd;
  1860. TrackMouseEvent(&tme);
  1861. ShowSSToolbar(TRUE);
  1862. KillTimer(TIMER_TOOLBAR); // we keep the toolbar down for as long as mouse is over it
  1863. m_fTBTrack = TRUE;
  1864. }
  1865. }
  1866. fHandled = FALSE;
  1867. return 0;
  1868. }
  1869. BOOL CPreviewWnd::OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam)
  1870. {
  1871. if (SLIDESHOW_MODE == m_dwMode)
  1872. {
  1873. if (m_fToolbarHidden)
  1874. {
  1875. SetCursorState(SLIDESHOW_CURSOR_HIDDEN);
  1876. }
  1877. else
  1878. {
  1879. SetCursorState(SLIDESHOW_CURSOR_NORMAL);
  1880. }
  1881. return TRUE;
  1882. }
  1883. else if (m_fAnnotating)
  1884. {
  1885. if (DPA_GetPtrCount(m_hdpaSelectedAnnotations) > 0)
  1886. {
  1887. CSelectionTracker tracker;
  1888. _SetupAnnotatingTracker(tracker);
  1889. if (tracker.SetCursor(m_ctlPreview.m_hWnd, lParam))
  1890. return TRUE;
  1891. }
  1892. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1893. return TRUE;
  1894. }
  1895. else if (m_fCropping)
  1896. {
  1897. CSelectionTracker tracker;
  1898. _SetupCroppingTracker(tracker);
  1899. if (tracker.SetCursor(m_ctlPreview.m_hWnd, lParam))
  1900. return TRUE;
  1901. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1902. return TRUE;
  1903. }
  1904. return FALSE;
  1905. }
  1906. BOOL CPreviewWnd::GetColor(COLORREF * pref)
  1907. {
  1908. *pref = 0; // black
  1909. if (SLIDESHOW_MODE == m_dwMode)
  1910. {
  1911. return TRUE;
  1912. }
  1913. return FALSE;
  1914. }
  1915. BOOL CPreviewWnd::OnSetColor(HDC hdc)
  1916. {
  1917. if (SLIDESHOW_MODE == m_dwMode)
  1918. {
  1919. SetBkColor(hdc, 0); // black
  1920. SetTextColor(hdc, 0xffffff); // white
  1921. return TRUE;
  1922. }
  1923. return FALSE;
  1924. }
  1925. // IObjectWithSite
  1926. HRESULT CPreviewWnd::SetSite(IUnknown *punk)
  1927. {
  1928. IUnknown_Set(&m_punkSite, punk);
  1929. if (m_pcwndSlideShow)
  1930. {
  1931. m_pcwndSlideShow->SetSite(punk);
  1932. }
  1933. return S_OK;
  1934. }
  1935. // This function take the name of the file being previewed and converts it into a
  1936. // title for the Full Screen Preview window. In converting the title it take into
  1937. // account user preference settings for how to display the filename.
  1938. void CPreviewWnd::SetCaptionInfo(LPCTSTR pszPath)
  1939. {
  1940. TCHAR szTitle[MAX_PATH] = TEXT("");
  1941. TCHAR szDisplayName[MAX_PATH] = TEXT("");
  1942. SHFILEINFO sfi = {0};
  1943. //
  1944. // Default to pszPath for the caption
  1945. // pszPath is non-null before the decode is attempted
  1946. if (pszPath)
  1947. {
  1948. if (SHGetFileInfo(pszPath, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME | SHGFI_USEFILEATTRIBUTES))
  1949. {
  1950. StrCpyN(szTitle, sfi.szDisplayName, ARRAYSIZE(szTitle));
  1951. StrCatBuff(szTitle, TEXT(" - "), ARRAYSIZE(szTitle));
  1952. }
  1953. }
  1954. TCHAR szApp[64];
  1955. szApp[0] = 0;
  1956. LoadString(_Module.GetModuleInstance(), IDS_PROJNAME, szApp, ARRAYSIZE(szApp));
  1957. StrCatBuff(szTitle, szApp, ARRAYSIZE(szTitle));
  1958. SetWindowText(szTitle);
  1959. }
  1960. LRESULT CPreviewWnd::OnDestroy(UINT , WPARAM , LPARAM , BOOL& fHandled)
  1961. {
  1962. RevokeDragDrop(m_hWnd);
  1963. _RegisterForChangeNotify(FALSE);
  1964. FlushBitmapMessages();
  1965. fHandled = FALSE;
  1966. // Make sure we don't leak icons
  1967. ReplaceWindowIcon(m_hWnd, ICON_SMALL, NULL);
  1968. ReplaceWindowIcon(m_hWnd, ICON_BIG, NULL);
  1969. // release the image lists used by the toolbar.
  1970. HWND hwndTB = m_ctlToolbar.m_hWnd;
  1971. HIMAGELIST himl = (HIMAGELIST)::SendMessage(hwndTB, TB_GETHOTIMAGELIST, 0, 0);
  1972. ::SendMessage(hwndTB, TB_SETHOTIMAGELIST, 0, NULL);
  1973. ImageList_Destroy(himl);
  1974. himl = (HIMAGELIST)::SendMessage(hwndTB, TB_GETIMAGELIST, 0, 0);
  1975. ::SendMessage(hwndTB, TB_SETIMAGELIST, 0, NULL);
  1976. ImageList_Destroy(himl);
  1977. if (WINDOW_MODE == m_dwMode)
  1978. {
  1979. WINDOWPLACEMENT wp;
  1980. wp.length = sizeof(wp);
  1981. if (GetWindowPlacement(&wp))
  1982. {
  1983. HKEY hk;
  1984. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, REGSTR_SHIMGVW, 0, NULL,
  1985. REG_OPTION_NON_VOLATILE, KEY_WRITE,
  1986. NULL, &hk, NULL))
  1987. {
  1988. RegSetValueEx(hk, REGSTR_BOUNDS, NULL, REG_BINARY,
  1989. (BYTE*)&wp.rcNormalPosition, sizeof(wp.rcNormalPosition));
  1990. BOOL fIsMaximized = (wp.showCmd == SW_SHOWMAXIMIZED);
  1991. RegSetValueEx(hk, REGSTR_MAXIMIZED, NULL, REG_BINARY,
  1992. (BYTE*)&fIsMaximized, sizeof(fIsMaximized));
  1993. RegCloseKey(hk);
  1994. }
  1995. }
  1996. PostQuitMessage(0);
  1997. }
  1998. return 0;
  1999. }
  2000. HRESULT CPreviewWnd::GetCurrentIDList(LPITEMIDLIST *ppidl)
  2001. {
  2002. HRESULT hr = _GetItem(m_iCurSlide, ppidl);
  2003. if (FAILED(hr))
  2004. {
  2005. TCHAR szPath[MAX_PATH];
  2006. hr = PathFromImageData(szPath, ARRAYSIZE(szPath));
  2007. if (SUCCEEDED(hr))
  2008. {
  2009. hr = SHILCreateFromPath(szPath, ppidl, NULL);
  2010. }
  2011. }
  2012. return hr;
  2013. }
  2014. void CPreviewWnd::MenuPoint(LPARAM lParam, int *px, int *py)
  2015. {
  2016. if (-1 == lParam)
  2017. {
  2018. // message is from the keyboard, figure out where to place the window
  2019. RECT rc;
  2020. ::GetWindowRect(m_hWnd, &rc);
  2021. *px = ((rc.left + rc.right) / 2);
  2022. *py = ((rc.top + rc.bottom) / 2);
  2023. }
  2024. else
  2025. {
  2026. *px = GET_X_LPARAM(lParam);
  2027. *py = GET_Y_LPARAM(lParam);
  2028. }
  2029. }
  2030. #define ID_FIRST 1 // Context Menu ID's
  2031. #define ID_LAST 0x7fff
  2032. LRESULT CPreviewWnd::OnContextMenu(UINT , WPARAM wParam, LPARAM lParam, BOOL& fHandled)
  2033. {
  2034. if (!m_fAllowContextMenu)
  2035. return 0;
  2036. if (m_fCanAnnotate && m_fAnnotating && DPA_GetPtrCount(m_hdpaSelectedAnnotations) > 0)
  2037. {
  2038. HMENU hpopup = CreatePopupMenu();
  2039. if (hpopup)
  2040. {
  2041. CComBSTR bstrDelete;
  2042. CComBSTR bstrProperties;
  2043. if (bstrDelete.LoadString(IDS_DELETECMD) &&
  2044. bstrProperties.LoadString(IDS_PROPERTIESCMD))
  2045. {
  2046. if (AppendMenu(hpopup, MF_STRING, ID_DELETECMD, bstrDelete) &&
  2047. AppendMenu(hpopup, MF_STRING, ID_PROPERTIESCMD, bstrProperties))
  2048. {
  2049. int x, y;
  2050. MenuPoint(lParam, &x, &y);
  2051. TrackPopupMenu(hpopup, TPM_RIGHTBUTTON | TPM_LEFTALIGN, x, y, 0, m_hWnd, NULL);
  2052. }
  2053. }
  2054. DestroyMenu(hpopup);
  2055. }
  2056. return 0;
  2057. }
  2058. LPITEMIDLIST pidl;
  2059. HRESULT hr = GetCurrentIDList(&pidl); // gets the dynamically generated title for this window
  2060. if (SUCCEEDED(hr))
  2061. {
  2062. IContextMenu *pcm;
  2063. hr = SHGetUIObjectFromFullPIDL(pidl, NULL, IID_PPV_ARG(IContextMenu, &pcm));
  2064. if (SUCCEEDED(hr))
  2065. {
  2066. HMENU hpopup = CreatePopupMenu();
  2067. if (hpopup)
  2068. {
  2069. // SetSite required if you want in place navigation
  2070. IUnknown_SetSite(pcm, SAFECAST(this, IServiceProvider *));
  2071. hr = pcm->QueryContextMenu(hpopup, 0, ID_FIRST, ID_LAST, CMF_NORMAL);
  2072. if (SUCCEEDED(hr))
  2073. {
  2074. int x, y;
  2075. MenuPoint(lParam, &x, &y);
  2076. ASSERT(_pcm3 == NULL);
  2077. pcm->QueryInterface(IID_PPV_ARG(IContextMenu3, &_pcm3));
  2078. // if there's a separator after "copy", remove it
  2079. UINT uCopy = GetMenuIndexForCanonicalVerb(hpopup, pcm,ID_FIRST, L"copy");
  2080. if (uCopy != -1)
  2081. {
  2082. UINT uState = GetMenuState(hpopup, uCopy+1, MF_BYPOSITION);
  2083. if (-1 != uState && (uState & MF_SEPARATOR))
  2084. {
  2085. RemoveMenu(hpopup, uCopy+1, MF_BYPOSITION);
  2086. }
  2087. }
  2088. ContextMenu_DeleteCommandByName(pcm, hpopup, ID_FIRST, L"link");
  2089. ContextMenu_DeleteCommandByName(pcm, hpopup, ID_FIRST, L"cut");
  2090. ContextMenu_DeleteCommandByName(pcm, hpopup, ID_FIRST, L"copy");
  2091. // the shell may have added a static Preview verb
  2092. ContextMenu_DeleteCommandByName(pcm, hpopup, ID_FIRST, L"open");
  2093. if (!m_fPaused)
  2094. {
  2095. TogglePlayState();
  2096. }
  2097. if (SLIDESHOW_MODE == m_dwMode)
  2098. {
  2099. m_fIgnoreUITimers = TRUE;
  2100. }
  2101. int idCmd = TrackPopupMenu(hpopup, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
  2102. x, y, 0, m_hWnd, NULL);
  2103. ATOMICRELEASE(_pcm3);
  2104. if (idCmd > 0)
  2105. {
  2106. CMINVOKECOMMANDINFO cmdInfo =
  2107. {
  2108. sizeof(cmdInfo),
  2109. 0,
  2110. m_hWnd,
  2111. (LPSTR)MAKEINTRESOURCE(idCmd - ID_FIRST),
  2112. NULL,
  2113. NULL,
  2114. SW_NORMAL
  2115. };
  2116. TCHAR szCommandString[40] = TEXT("");
  2117. ContextMenu_GetCommandStringVerb(pcm, idCmd - ID_FIRST, szCommandString, ARRAYSIZE(szCommandString));
  2118. if (lstrcmpi(szCommandString, TEXT("edit")) == 0)
  2119. {
  2120. hr = _SaveIfDirty(TRUE);
  2121. if (S_OK != hr)
  2122. {
  2123. hr = E_ABORT;
  2124. }
  2125. }
  2126. if (SUCCEEDED(hr))
  2127. {
  2128. if (lstrcmpi(szCommandString, TEXT("print")) == 0)
  2129. {
  2130. _RefreshSelection(FALSE);
  2131. _InvokePrintWizard();
  2132. }
  2133. else
  2134. {
  2135. hr = pcm->InvokeCommand(&cmdInfo);
  2136. }
  2137. }
  2138. if (SUCCEEDED(hr))
  2139. {
  2140. if (lstrcmpi(szCommandString, TEXT("delete")) == 0)
  2141. {
  2142. _RemoveFromArray(m_iCurSlide);
  2143. _ShowNextSlide(FALSE);
  2144. }
  2145. else if (lstrcmpi(szCommandString, TEXT("edit")) == 0)
  2146. {
  2147. m_fDirty = FALSE;
  2148. m_fNoRestore = TRUE;
  2149. // RAID 414238: Image Preview Control
  2150. // Context menu "&Edit" causes image preview window
  2151. // to close, wrecking Explorer when in 'control mode'.
  2152. if (m_dwMode != CONTROL_MODE)
  2153. {
  2154. PostMessage(WM_CLOSE, 0, 0);
  2155. }
  2156. }
  2157. }
  2158. }
  2159. if (SLIDESHOW_MODE == m_dwMode)
  2160. {
  2161. SetTimer(TIMER_TOOLBAR, m_uTimeout);
  2162. m_fIgnoreUITimers = FALSE;
  2163. }
  2164. }
  2165. IUnknown_SetSite(pcm, NULL);
  2166. DestroyMenu(hpopup);
  2167. }
  2168. pcm->Release();
  2169. }
  2170. ILFree(pidl);
  2171. }
  2172. return 0;
  2173. }
  2174. int ClearCB(void *p, void *pData)
  2175. {
  2176. SHFree(p);
  2177. return 1;
  2178. }
  2179. void CPreviewWnd::_ClearDPA()
  2180. {
  2181. if (m_ppidls)
  2182. {
  2183. for (UINT i = 0; i < m_cItems; i++)
  2184. ILFree(m_ppidls[i]);
  2185. CoTaskMemFree(m_ppidls);
  2186. m_ppidls = NULL;
  2187. }
  2188. m_cItems = 0;
  2189. m_iCurSlide = 0;
  2190. }
  2191. HRESULT CPreviewWnd::SetWallpaper(BSTR pszPath)
  2192. {
  2193. return SUCCEEDED(SetWallpaperHelper(pszPath)) ? S_OK : S_FALSE;
  2194. }
  2195. HRESULT CPreviewWnd::StartSlideShow(IUnknown *punkToView)
  2196. {
  2197. HRESULT hr = E_FAIL;
  2198. if (NULL == punkToView)
  2199. punkToView = m_punkSite;
  2200. if (SLIDESHOW_MODE == m_dwMode)
  2201. {
  2202. // these are required for slideshow
  2203. KillTimer(TIMER_SLIDESHOW);
  2204. SetCursorState(SLIDESHOW_CURSOR_HIDDEN);
  2205. m_fGoBack = FALSE;
  2206. // if slide show was reopened cancel any previous tracking
  2207. TRACKMOUSEEVENT tme = {0};
  2208. tme.cbSize = sizeof(tme);
  2209. tme.dwFlags = TME_CANCEL | TME_LEAVE;
  2210. tme.hwndTrack = m_ctlToolbar.m_hWnd;
  2211. TrackMouseEvent(&tme);
  2212. m_fTBTrack = FALSE;
  2213. if (punkToView)
  2214. hr = PreviewItemsFromUnk(punkToView);
  2215. else
  2216. hr = _PreviewItem(m_iCurSlide);
  2217. if (SUCCEEDED(hr))
  2218. m_fPaused = FALSE;
  2219. }
  2220. else
  2221. {
  2222. //create the slide show window
  2223. // Full Screen
  2224. if (m_pcwndSlideShow && m_pcwndSlideShow->m_hWnd)
  2225. {
  2226. RestoreAndActivate(m_pcwndSlideShow->m_hWnd);
  2227. }
  2228. else
  2229. {
  2230. // create the window
  2231. if (!m_pcwndSlideShow)
  2232. {
  2233. m_pcwndSlideShow = new CPreviewWnd();
  2234. if (!m_pcwndSlideShow)
  2235. {
  2236. // out of memory
  2237. return E_OUTOFMEMORY;
  2238. }
  2239. else
  2240. {
  2241. if (FAILED(m_pcwndSlideShow->Initialize(this, SLIDESHOW_MODE, FALSE)))
  2242. {
  2243. return E_OUTOFMEMORY;
  2244. }
  2245. }
  2246. }
  2247. m_pcwndSlideShow->m_iCurSlide = m_iCurSlide; // so the slide show stays in sync
  2248. RECT rc = { 0,0,GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)};
  2249. m_pcwndSlideShow->Create(NULL, rc, NULL, WS_VISIBLE | WS_POPUP);
  2250. }
  2251. hr = m_pcwndSlideShow->StartSlideShow(NULL);
  2252. }
  2253. return hr;
  2254. }
  2255. HRESULT CPreviewWnd::_GetItem(UINT iItem, LPITEMIDLIST *ppidl)
  2256. {
  2257. HRESULT hr = E_FAIL;
  2258. if (iItem < m_cItems)
  2259. {
  2260. hr = SHILClone(m_ppidls[iItem], ppidl);
  2261. }
  2262. return hr;
  2263. }
  2264. void CPreviewWnd::_RemoveFromArray(UINT iItem)
  2265. {
  2266. if (iItem < m_cItems)
  2267. {
  2268. ILFree(m_ppidls[iItem]); // this one is now gone
  2269. // slide all other pidls down in the array
  2270. for (UINT i = iItem + 1; i < m_cItems; i++)
  2271. {
  2272. m_ppidls[i - 1] = m_ppidls[i];
  2273. }
  2274. m_cItems--;
  2275. m_ppidls[m_cItems] = NULL; // make sure stale ptr is now NULL
  2276. // if we deleted an item before m_iCurSlide then we must adjust m_iCurSlide
  2277. if (iItem < m_iCurSlide)
  2278. {
  2279. m_iCurSlide--;
  2280. }
  2281. else if (m_iCurSlide == m_cItems)
  2282. {
  2283. m_iCurSlide = 0;
  2284. }
  2285. // Now prepare for "ShowNextSlide"
  2286. if (!m_iCurSlide)
  2287. {
  2288. m_iCurSlide = m_cItems ? m_cItems-1 : 0;
  2289. }
  2290. else
  2291. {
  2292. m_iCurSlide--;
  2293. }
  2294. // make sure the prefetch task has the right index
  2295. if (m_pNextImageData)
  2296. {
  2297. if (!(m_pNextImageData->_iItem) && iItem && m_cItems)
  2298. {
  2299. m_pNextImageData->_iItem = m_cItems-1;
  2300. }
  2301. else if (m_pNextImageData->_iItem > iItem)
  2302. {
  2303. m_pNextImageData->_iItem--;
  2304. }
  2305. else
  2306. {
  2307. FlushBitmapMessages();
  2308. ATOMICRELEASE(m_pNextImageData);
  2309. }
  2310. }
  2311. }
  2312. }
  2313. HRESULT CPreviewWnd::_DeleteCurrentSlide()
  2314. {
  2315. LPITEMIDLIST pidl;
  2316. HRESULT hr = _GetItem(m_iCurSlide, &pidl);
  2317. if (SUCCEEDED(hr))
  2318. {
  2319. TCHAR szPath[MAX_PATH + 1] = {0}; // +1 and zero init for dbl NULL terminate extra terminator
  2320. DWORD dwAttribs = SFGAO_FILESYSTEM | SFGAO_STREAM;
  2321. hr = SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath)-1, &dwAttribs);
  2322. if (SUCCEEDED(hr))
  2323. {
  2324. BOOL fSuccess = TRUE;
  2325. if (dwAttribs & SFGAO_FILESYSTEM)
  2326. {
  2327. SHFILEOPSTRUCT fo = {0};
  2328. fo.hwnd = m_hWnd;
  2329. fo.wFunc = FO_DELETE;
  2330. fo.pFrom = szPath;
  2331. fo.fFlags = FOF_ALLOWUNDO;
  2332. fo.fAnyOperationsAborted = FALSE;
  2333. if (SHFileOperation(&fo) == ERROR_SUCCESS)
  2334. {
  2335. if (fo.fAnyOperationsAborted == TRUE)
  2336. fSuccess = FALSE;
  2337. }
  2338. }
  2339. else
  2340. {
  2341. _InvokeVerb(TEXT("delete"));
  2342. // We have to assume success since there is no way to know if the user
  2343. // cancelled the confirmation dialog without hitting the camera again.
  2344. }
  2345. if (fSuccess)
  2346. {
  2347. m_fDirty = FALSE;
  2348. _RemoveFromArray(m_iCurSlide);
  2349. _ShowNextSlide(FALSE);
  2350. }
  2351. }
  2352. ILFree(pidl);
  2353. }
  2354. return hr;
  2355. }
  2356. // index can be either current or next slide so that user can click multiple times on next/prev button
  2357. HRESULT CPreviewWnd::_ShowNextSlide(BOOL bGoBack)
  2358. {
  2359. HRESULT hr = E_FAIL;
  2360. if (m_cItems)
  2361. {
  2362. if (bGoBack)
  2363. {
  2364. if (m_iCurSlide)
  2365. m_iCurSlide--;
  2366. else
  2367. m_iCurSlide = m_cItems - 1;
  2368. }
  2369. else
  2370. {
  2371. m_iCurSlide++;
  2372. if (m_iCurSlide >= m_cItems)
  2373. m_iCurSlide = 0;
  2374. }
  2375. if (!m_fPaused)
  2376. {
  2377. SetTimer(TIMER_SLIDESHOW, m_uTimeout);
  2378. }
  2379. SetTimer(TIMER_BUSYCURSOR, 500);
  2380. LPITEMIDLIST pidl;
  2381. // set the caption in case the load fails
  2382. if (SUCCEEDED(_GetItem(m_iCurSlide, &pidl)))
  2383. {
  2384. TCHAR szPath[MAX_PATH];
  2385. if (SUCCEEDED(SHGetNameAndFlags(pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, szPath, ARRAYSIZE(szPath)-1, NULL)))
  2386. {
  2387. SetCaptionInfo(szPath);
  2388. }
  2389. else
  2390. {
  2391. SetCaptionInfo(NULL);
  2392. }
  2393. ILFree(pidl);
  2394. }
  2395. hr = _PreviewItem(m_iCurSlide);
  2396. if (SUCCEEDED(hr))
  2397. {
  2398. _PreLoadItem((m_iCurSlide + 1) % m_cItems);
  2399. }
  2400. }
  2401. return hr;
  2402. }
  2403. HRESULT CPreviewWnd::_StartDecode(UINT iItem, BOOL fUpdateCaption)
  2404. {
  2405. LPITEMIDLIST pidl;
  2406. HRESULT hr = _GetItem(iItem, &pidl);
  2407. if (SUCCEEDED(hr))
  2408. {
  2409. TCHAR szPath[MAX_PATH];
  2410. DWORD dwAttribs = SFGAO_FILESYSTEM | SFGAO_STREAM;
  2411. hr = SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath), &dwAttribs);
  2412. if (SUCCEEDED(hr) && (dwAttribs & SFGAO_FILESYSTEM))
  2413. {
  2414. hr = _PreviewFromFile(szPath, iItem, fUpdateCaption);
  2415. }
  2416. else if (dwAttribs & SFGAO_STREAM)
  2417. {
  2418. // this might not be a file system object, try to bind to it via IStream
  2419. IStream *pstrm;
  2420. hr = SHBindToObject(NULL, IID_X_PPV_ARG(IStream, pidl, &pstrm));
  2421. if (SUCCEEDED(hr))
  2422. {
  2423. hr = _PreviewFromStream(pstrm, iItem, fUpdateCaption);
  2424. pstrm->Release();
  2425. }
  2426. }
  2427. else
  2428. {
  2429. // funky attributes?
  2430. hr = S_FALSE;
  2431. }
  2432. ILFree(pidl);
  2433. }
  2434. return hr;
  2435. }
  2436. HRESULT CPreviewWnd::_PreLoadItem(UINT iItem)
  2437. {
  2438. HRESULT hr = _StartDecode(iItem, FALSE);
  2439. if (SUCCEEDED(hr))
  2440. {
  2441. m_iDecodingNextImage = iItem;
  2442. }
  2443. return hr;
  2444. }
  2445. HRESULT CPreviewWnd::_PreviewItem(UINT iItem)
  2446. {
  2447. HRESULT hr = S_OK;
  2448. if ((SLIDESHOW_MODE == m_dwMode) && (0 == m_cItems)) // if no more items, user just deleted the last one, so quit the slideshow
  2449. {
  2450. _CloseSlideshowWindow();
  2451. }
  2452. else
  2453. {
  2454. if (!_TrySetImage())
  2455. {
  2456. // If we are not currently already decoding this item, let's get cranking!
  2457. if (m_iDecodingNextImage != iItem)
  2458. {
  2459. hr = _StartDecode(iItem, TRUE);
  2460. }
  2461. StatusUpdate((S_OK == hr) ? IDS_LOADING : IDS_LOADFAILED);
  2462. }
  2463. }
  2464. return hr;
  2465. }
  2466. int CPreviewWnd::TranslateAccelerator(MSG *pmsg)
  2467. {
  2468. if (IsVK_TABCycler(pmsg))
  2469. {
  2470. if (OnNonSlideShowTab())
  2471. {
  2472. return TRUE;
  2473. }
  2474. }
  2475. else if (m_haccel)
  2476. {
  2477. ASSERT(m_hWnd);
  2478. return ::TranslateAccelerator(m_hWnd, m_haccel, pmsg);
  2479. }
  2480. return FALSE;
  2481. }
  2482. // Sent when the image generation status has changed, once when the image is first
  2483. // being created and again if there is an error of any kind. This should invalidate
  2484. // and free any left over bitmap and the cached copy of the previous m_ImgCtx
  2485. void CPreviewWnd::StatusUpdate(int iStatus)
  2486. {
  2487. if (m_pImageData)
  2488. {
  2489. m_pImageData->Release();
  2490. m_pImageData = NULL;
  2491. }
  2492. //
  2493. // the caption is set at the first attempt to load an image
  2494. m_ctlPreview.StatusUpdate(iStatus);
  2495. _SetMultipageCommands();
  2496. _SetMultiImagesCommands();
  2497. _SetAnnotatingCommands(FALSE);
  2498. _SetEditCommands();
  2499. m_fPrintable = FALSE;
  2500. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_PRINTCMD, MAKELONG(m_fPrintable, 0));
  2501. // update our toolbar
  2502. BOOL fHandled;
  2503. OnSize(0x0, 0, 0, fHandled);
  2504. }
  2505. // Return:
  2506. // S_OK walk succeeded, image files found to preview: display new images in preview
  2507. // S_FALSE walk cancelled (by user): display existing image in preview (no change)
  2508. // E_XXXX walk failed: display no image in preview
  2509. //
  2510. HRESULT CPreviewWnd::WalkItemsToPreview(IUnknown* punk)
  2511. {
  2512. HRESULT hr = _SaveIfDirty(TRUE);
  2513. if (FAILED(hr) || hr == S_FALSE)
  2514. return hr;
  2515. m_fFirstItem = TRUE;
  2516. _ClearDPA(); // clean up old stuff
  2517. INamespaceWalk *pnsw;
  2518. hr = CoCreateInstance(CLSID_NamespaceWalker, NULL, CLSCTX_INPROC, IID_PPV_ARG(INamespaceWalk, &pnsw));
  2519. if (SUCCEEDED(hr))
  2520. {
  2521. // in control mode we only dislay one item at a time. lets setup our
  2522. // state so this can work just like the other modes
  2523. DWORD dwFlags = (CONTROL_MODE == m_dwMode) ? 0 : NSWF_ONE_IMPLIES_ALL | NSWF_NONE_IMPLIES_ALL;
  2524. m_fClosed = FALSE;
  2525. hr = pnsw->Walk(punk, dwFlags, m_cWalkDepth, SAFECAST(this, INamespaceWalkCB *));
  2526. // the window might have been closed during the namespace walk
  2527. if (WINDOW_MODE == m_dwMode && m_fClosed)
  2528. {
  2529. hr = E_FAIL;
  2530. }
  2531. if (SUCCEEDED(hr))
  2532. {
  2533. hr = pnsw->GetIDArrayResult(&m_cItems, &m_ppidls);
  2534. if (SUCCEEDED(hr) && (m_dwMode == WINDOW_MODE) && m_cItems && m_fFirstTime)
  2535. {
  2536. m_fFirstTime = FALSE;
  2537. SHAddToRecentDocs(SHARD_PIDL, m_ppidls[0]);
  2538. }
  2539. }
  2540. pnsw->Release();
  2541. }
  2542. // Clarification of INamespaceWalk return values:
  2543. // S_OK walk has succeeded, and image files found to preview
  2544. // S_FALSE walk has succeeded, but no image files found to preview
  2545. // **** convert to E_FAIL to keep in line with return of function
  2546. // E_XXXX walk has failed
  2547. //
  2548. return hr == S_FALSE ? E_FAIL : hr;
  2549. }
  2550. void CPreviewWnd::PreviewItems()
  2551. {
  2552. if (WINDOW_MODE == m_dwMode)
  2553. {
  2554. RestoreAndActivate(m_hWnd);
  2555. }
  2556. _PreviewItem(0);
  2557. if (SLIDESHOW_MODE == m_dwMode)
  2558. {
  2559. if (m_cItems > 1)
  2560. {
  2561. _PreLoadItem(1);
  2562. }
  2563. }
  2564. }
  2565. // build the _ppidl and m_cItems members and preview the first one
  2566. HRESULT CPreviewWnd::PreviewItemsFromUnk(IUnknown *punk)
  2567. {
  2568. HRESULT hr = WalkItemsToPreview(punk);
  2569. if (SUCCEEDED(hr))
  2570. {
  2571. if (S_FALSE != hr)
  2572. PreviewItems();
  2573. }
  2574. else
  2575. {
  2576. StatusUpdate(IDS_LOADFAILED);
  2577. }
  2578. return hr;
  2579. }
  2580. // If the "new" image is the same as the old image, and the old image was recently edited then we assume that
  2581. // the reason we are getting a new ShowFile request is due to an FSChangeNotify on the file. We also assume
  2582. // that we are the cause of this change notify. Further we assume that we already have the correctly decoded
  2583. // image still ready. These are assumptions which might not be TRUE 100%, in which case we will do really
  2584. // strange things, but they should be TRUE 99.9% of the time which is considered "good enough". The reason we
  2585. // make these dangerous assumptions is to prevent decoding the image again and thus flickering between the
  2586. // old image, the "generating preview..." message, and the new (identical) image.
  2587. BOOL CPreviewWnd::_ReShowingSameFile(LPCTSTR pszNewFile)
  2588. {
  2589. BOOL bIsSameFile = FALSE;
  2590. if (m_pImageData)
  2591. {
  2592. if (pszNewFile && m_fWasEdited)
  2593. {
  2594. m_fWasEdited = FALSE;
  2595. TCHAR szOldPath[MAX_PATH];
  2596. if ((S_OK == PathFromImageData(szOldPath, ARRAYSIZE(szOldPath))) &&
  2597. (0 == StrCmpI(szOldPath, pszNewFile)))
  2598. {
  2599. if (m_pEvents)
  2600. m_pEvents->OnPreviewReady();
  2601. bIsSameFile = TRUE;
  2602. }
  2603. }
  2604. if (!bIsSameFile)
  2605. {
  2606. m_pImageData->Release(); // need to start clean
  2607. m_pImageData = NULL;
  2608. }
  2609. }
  2610. return bIsSameFile;
  2611. }
  2612. // pszFile may be NULL. cItems expresses how many are selected so we can
  2613. // display "multiple items selected" and not display anything.
  2614. LRESULT CPreviewWnd::ShowFile(LPCTSTR pszFile, UINT cItems, BOOL fReshow)
  2615. {
  2616. if (!m_hWnd)
  2617. return S_FALSE;
  2618. HRESULT hr = S_FALSE;
  2619. TCHAR szLongName[MAX_PATH]; // short file names are UGLY
  2620. if (GetLongPathName(pszFile, szLongName, ARRAYSIZE(szLongName)))
  2621. {
  2622. pszFile = szLongName;
  2623. }
  2624. if (!fReshow && _ReShowingSameFile(pszFile))
  2625. return S_FALSE;
  2626. // It is possible that there is already a bitmap message in our queue from the previous rendering.
  2627. // If this is the case we should remove that message and release its bitmap before we continue.
  2628. // If we do not then that message will get processed and will send the OnPreviewReady event to the
  2629. // obejct container but this event might no longer be valid.
  2630. FlushBitmapMessages();
  2631. if (pszFile && *pszFile)
  2632. {
  2633. IDataObject *pdtobj;
  2634. hr = GetUIObjectFromPath(pszFile, IID_PPV_ARG(IDataObject, &pdtobj));
  2635. if (SUCCEEDED(hr))
  2636. {
  2637. hr = PreviewItemsFromUnk(pdtobj);
  2638. m_fPaused = TRUE;
  2639. pdtobj->Release();
  2640. }
  2641. }
  2642. else
  2643. {
  2644. int iRetCode = (cItems > 1) ? IDS_MULTISELECT : IDS_NOPREVIEW;
  2645. // Set the Return Code into all owned zoom windows. This instructs these windows to disregard
  2646. // their previous images and display the status message instead.
  2647. StatusUpdate(iRetCode);
  2648. }
  2649. return hr;
  2650. }
  2651. LRESULT CPreviewWnd::IV_OnIVScroll(UINT , WPARAM , LPARAM lParam, BOOL&)
  2652. {
  2653. DWORD nHCode = LOWORD(lParam);
  2654. DWORD nVCode = HIWORD(lParam);
  2655. if (nHCode)
  2656. {
  2657. m_ctlPreview.SendMessage(WM_HSCROLL, nHCode, NULL);
  2658. }
  2659. if (nVCode)
  2660. {
  2661. m_ctlPreview.SendMessage(WM_VSCROLL, nVCode, NULL);
  2662. }
  2663. return 0;
  2664. }
  2665. // IV_OnSetOptions
  2666. //
  2667. // This message is sent to turn on or off all the optional features of the image preview control.
  2668. // NOTE: When used as a control this function is called BEFORE the window is created. Don't do
  2669. // anything in this function that will fail without a window unless you check for this condition.
  2670. LRESULT CPreviewWnd::IV_OnSetOptions(UINT , WPARAM wParam, LPARAM lParam, BOOL&)
  2671. {
  2672. BOOL bResult = TRUE;
  2673. // Boolify lParam just to be safe.
  2674. lParam = lParam ? 1:0;
  2675. switch (wParam)
  2676. {
  2677. case IVO_TOOLBAR:
  2678. if ((BOOL)lParam != m_fShowToolbar)
  2679. {
  2680. m_fShowToolbar = (BOOL)lParam;
  2681. if (m_hWnd)
  2682. {
  2683. if (m_fShowToolbar)
  2684. {
  2685. if (!m_ctlToolbar)
  2686. {
  2687. bResult = CreateToolbar();
  2688. if (!bResult)
  2689. {
  2690. m_fShowToolbar = FALSE;
  2691. break;
  2692. }
  2693. }
  2694. }
  2695. else
  2696. {
  2697. if (m_ctlToolbar)
  2698. {
  2699. m_ctlToolbar.DestroyWindow();
  2700. }
  2701. }
  2702. }
  2703. }
  2704. break;
  2705. case IVO_PRINTBTN:
  2706. if ((BOOL)lParam != m_fHidePrintBtn)
  2707. {
  2708. m_fHidePrintBtn = (BOOL)lParam;
  2709. if (m_hWnd && m_ctlToolbar)
  2710. {
  2711. m_ctlToolbar.SendMessage(TB_HIDEBUTTON,ID_PRINTCMD,lParam);
  2712. }
  2713. }
  2714. break;
  2715. case IVO_CONTEXTMENU:
  2716. m_fAllowContextMenu = (BOOL)lParam;
  2717. break;
  2718. case IVO_PRINTABLE:
  2719. TraceMsg(TF_WARNING, "Obsolete IVO_PRINTABLE option received.");
  2720. break;
  2721. case IVO_DISABLEEDIT:
  2722. m_fDisableEdit = (BOOL)lParam;
  2723. break;
  2724. default:
  2725. break;
  2726. }
  2727. return bResult;
  2728. }
  2729. void CPreviewWnd::_SetEditCommands()
  2730. {
  2731. if (CONTROL_MODE != m_dwMode)
  2732. {
  2733. // We can save if we have a file; the save dialog will show the available encoders
  2734. BOOL fCanSave = m_pImageData ? TRUE : FALSE;
  2735. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_SAVEASCMD, MAKELONG(!fCanSave, 0));
  2736. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_SAVEASCMD, MAKELONG(fCanSave, 0));
  2737. }
  2738. BOOL fCanRotate = m_pImageData != NULL;
  2739. if (CONTROL_MODE != m_dwMode)
  2740. {
  2741. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_ROTATESEP, MAKELONG(!fCanRotate, 0));
  2742. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_ROTATE90CMD, MAKELONG(!fCanRotate, 0));
  2743. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_ROTATE270CMD, MAKELONG(!fCanRotate, 0));
  2744. }
  2745. else
  2746. {
  2747. // we don't rotate multi-page images in control mode
  2748. fCanRotate = fCanRotate && !m_pImageData->IsMultipage();
  2749. }
  2750. // No matter where we are GDIPlus can't rotate WMF or EMF files. Curiously,
  2751. // we will let you rotate ICO files, but because we don't have an encoder
  2752. // we won't save them :)
  2753. if (fCanRotate)
  2754. {
  2755. fCanRotate = !(IsEqualGUID(ImageFormatWMF, m_pImageData->_guidFormat) ||
  2756. IsEqualGUID(ImageFormatEMF, m_pImageData->_guidFormat) ||
  2757. m_pImageData->IsAnimated());
  2758. }
  2759. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_ROTATESEP, MAKELONG(fCanRotate, 0));
  2760. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_ROTATE90CMD, MAKELONG(fCanRotate, 0));
  2761. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_ROTATE270CMD, MAKELONG(fCanRotate, 0));
  2762. TCHAR szFile[MAX_PATH];
  2763. BOOL fCanOpen = SUCCEEDED(PathFromImageData(szFile, ARRAYSIZE(szFile)));
  2764. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_OPENCMD, MAKELONG(fCanOpen, 0));
  2765. }
  2766. void CPreviewWnd::_UpdatePageNumber()
  2767. {
  2768. TCHAR szText[20];
  2769. wsprintf(szText, TEXT("%d"), m_pImageData->_iCurrent+1);
  2770. TBBUTTONINFO bi = {0};
  2771. bi.cbSize = sizeof(bi);
  2772. bi.dwMask = TBIF_TEXT | TBIF_STATE;
  2773. bi.fsState = TBSTATE_ENABLED;
  2774. bi.pszText = szText;
  2775. m_ctlToolbar.SendMessage(TB_SETBUTTONINFO, ID_PAGELIST, (LPARAM)&bi);
  2776. }
  2777. void CPreviewWnd::_SetMultipageCommands()
  2778. {
  2779. DWORD dwMode;
  2780. // this code relies on the fact that TIFFs are the only multipage format we view
  2781. if (!m_pImageData || m_pImageData->_guidFormat != ImageFormatTIFF )
  2782. {
  2783. dwMode = MPCMD_HIDDEN;
  2784. }
  2785. else if (!m_pImageData->IsMultipage())
  2786. {
  2787. dwMode = MPCMD_DISABLED;
  2788. }
  2789. else if (m_pImageData->IsFirstPage())
  2790. {
  2791. dwMode = MPCMD_FIRSTPAGE;
  2792. }
  2793. else if (m_pImageData->IsLastPage())
  2794. {
  2795. dwMode = MPCMD_LASTPAGE;
  2796. }
  2797. else
  2798. {
  2799. dwMode = MPCMD_MIDDLEPAGE;
  2800. }
  2801. // remember which buttons are enabled/hidden so we can quickly create our context menu
  2802. if (dwMode != m_dwMultiPageMode)
  2803. {
  2804. m_dwMultiPageMode = dwMode;
  2805. if (CONTROL_MODE != m_dwMode)
  2806. {
  2807. // Switch accelerator tables so that Page Up and Page Down work
  2808. if (dwMode == MPCMD_HIDDEN || dwMode == MPCMD_DISABLED)
  2809. {
  2810. m_haccel = LoadAccelerators(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDA_PREVWND_SINGLEPAGE));
  2811. }
  2812. else
  2813. {
  2814. m_haccel = LoadAccelerators(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDA_PREVWND_MULTIPAGE));
  2815. }
  2816. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_PAGECMDSEP, MAKELONG((MPCMD_HIDDEN==dwMode),0));
  2817. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_PREVPAGECMD, MAKELONG((MPCMD_HIDDEN==dwMode),0));
  2818. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_PAGELIST, MAKELONG((MPCMD_HIDDEN==dwMode),0));
  2819. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_NEXTPAGECMD, MAKELONG((MPCMD_HIDDEN==dwMode),0));
  2820. if (MPCMD_HIDDEN != dwMode)
  2821. {
  2822. _UpdatePageNumber();
  2823. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_PREVPAGECMD, MAKELONG((MPCMD_FIRSTPAGE!=dwMode && MPCMD_DISABLED!=dwMode),0));
  2824. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_NEXTPAGECMD, MAKELONG((MPCMD_LASTPAGE !=dwMode && MPCMD_DISABLED!=dwMode),0));
  2825. }
  2826. }
  2827. }
  2828. else
  2829. {
  2830. if (CONTROL_MODE != m_dwMode)
  2831. {
  2832. if (dwMode == MPCMD_MIDDLEPAGE)
  2833. {
  2834. _UpdatePageNumber();
  2835. }
  2836. }
  2837. }
  2838. }
  2839. void CPreviewWnd::_SetMultiImagesCommands()
  2840. {
  2841. BOOL bHasFiles = m_cItems;
  2842. if (CONTROL_MODE != m_dwMode)
  2843. {
  2844. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_PREVIMGCMD, MAKELONG(!bHasFiles, 0));
  2845. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_NEXTIMGCMD, MAKELONG(!bHasFiles, 0));
  2846. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_VIEWCMDSEP, MAKELONG(!bHasFiles, 0));
  2847. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_PREVIMGCMD, MAKELONG(bHasFiles, 0));
  2848. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_NEXTIMGCMD, MAKELONG(bHasFiles, 0));
  2849. }
  2850. }
  2851. HRESULT CPreviewWnd::PathFromImageData(LPTSTR pszFile, UINT cch)
  2852. {
  2853. *pszFile = 0;
  2854. IShellImageData *pSID;
  2855. HRESULT hr = m_pImageData ? m_pImageData->Lock(&pSID) : E_FAIL;
  2856. if (SUCCEEDED(hr))
  2857. {
  2858. IPersistFile *ppf;
  2859. hr = pSID->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
  2860. if (SUCCEEDED(hr))
  2861. {
  2862. WCHAR *psz;
  2863. hr = ppf->GetCurFile(&psz);
  2864. if (SUCCEEDED(hr))
  2865. {
  2866. lstrcpyn(pszFile, psz, cch);
  2867. CoTaskMemFree(psz);
  2868. }
  2869. ppf->Release();
  2870. }
  2871. m_pImageData->Unlock();
  2872. }
  2873. return hr;
  2874. }
  2875. HRESULT CPreviewWnd::ImageDataSave(LPCTSTR pszFile, BOOL bShowUI)
  2876. {
  2877. IShellImageData * pSID = NULL;
  2878. HRESULT hr = m_pImageData ? m_pImageData->Lock(&pSID) : E_FAIL;
  2879. Image *pimgRestore = NULL;
  2880. if (SUCCEEDED(hr))
  2881. {
  2882. GUID guidFmt = GUID_NULL;
  2883. BOOL bSave = TRUE;
  2884. BOOL bWarnBurn = FALSE;
  2885. BOOL bRestoreParams = FALSE;
  2886. pSID->GetRawDataFormat(&guidFmt);
  2887. // if saving to a jpeg, set the image quality to high
  2888. // if pszFile is NULL, we're saving the same file, so don't promote the image quality
  2889. if (pszFile)
  2890. {
  2891. m_pImageFactory->GetDataFormatFromPath(pszFile, &guidFmt);
  2892. if (guidFmt == ImageFormatJPEG )
  2893. {
  2894. IPropertyBag *ppb;
  2895. if (SUCCEEDED(SHCreatePropertyBagOnMemory(STGM_READWRITE,
  2896. IID_PPV_ARG(IPropertyBag, &ppb))))
  2897. {
  2898. // write the quality value for the recompression into the property bag
  2899. // we have to write the format too...CImageData relies on "all or nothing"
  2900. // from the encoder params property bag
  2901. VARIANT var;
  2902. hr = InitVariantFromGUID(&var, ImageFormatJPEG);
  2903. if (SUCCEEDED(hr))
  2904. {
  2905. ppb->Write(SHIMGKEY_RAWFORMAT, &var);
  2906. VariantClear(&var);
  2907. }
  2908. SHPropertyBag_WriteInt(ppb, SHIMGKEY_QUALITY, 100);
  2909. pSID->SetEncoderParams(ppb);
  2910. ppb->Release();
  2911. bRestoreParams = TRUE;
  2912. }
  2913. }
  2914. }
  2915. if (bShowUI && pszFile)
  2916. {
  2917. // warn the user if saving from TIFF to something that will lose annotations
  2918. BOOL bDestTiff = ImageFormatTIFF == guidFmt;
  2919. BOOL bAnnot = m_ctlPreview.GetAnnotations()->GetCount() > 0;
  2920. bWarnBurn = bAnnot && !bDestTiff;
  2921. #if 0
  2922. if (!bWarnBurn && S_OK == m_pImageData->IsMultipage() && !bDestTiff)
  2923. {
  2924. GUID guidFmt;
  2925. bWarnBurn = TRUE;
  2926. if (SUCCEEDED(m_pImageFactory->GetDataFormatFromPath(pszFile, &guidFmt)))
  2927. {
  2928. bWarn = !FmtSupportsMultiPage(pSID, &guidFmt);
  2929. }
  2930. }
  2931. #endif // 0 Put the multipage warning back in if needed, and change the wording of IDS_SAVE_WARN_TIFF
  2932. }
  2933. if (bWarnBurn)
  2934. {
  2935. m_fPromptingUser = TRUE;
  2936. bSave = (IDYES == ShellMessageBox(_Module.GetModuleInstance(), m_hWnd,
  2937. MAKEINTRESOURCE(IDS_SAVE_WARN_TIFF),
  2938. MAKEINTRESOURCE(IDS_PROJNAME),
  2939. MB_YESNO | MB_ICONINFORMATION));
  2940. m_fPromptingUser = FALSE;
  2941. if (bSave)
  2942. {
  2943. // Save the current image frame to restore after the save to a different file is complete
  2944. pimgRestore = _BurnAnnotations(pSID);
  2945. }
  2946. }
  2947. if (bSave)
  2948. {
  2949. IPersistFile *ppf;
  2950. hr = pSID->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
  2951. if (SUCCEEDED(hr))
  2952. {
  2953. // if saving to the same file name, make sure
  2954. // the changenotify code ignores the notify this will generate
  2955. //
  2956. if (!pszFile)
  2957. {
  2958. m_fIgnoreNextNotify = TRUE;
  2959. }
  2960. hr = ppf->Save(pszFile, FALSE);
  2961. if (SUCCEEDED(hr))
  2962. {
  2963. m_fWasEdited = TRUE;
  2964. }
  2965. else if (!pszFile)
  2966. {
  2967. m_fIgnoreNextNotify = FALSE;
  2968. }
  2969. }
  2970. ppf->Release();
  2971. if (pimgRestore)
  2972. {
  2973. pSID->ReplaceFrame(pimgRestore);
  2974. }
  2975. }
  2976. else
  2977. {
  2978. hr = S_FALSE; // we did nothing
  2979. }
  2980. if (bRestoreParams)
  2981. {
  2982. pSID->SetEncoderParams(NULL);
  2983. }
  2984. m_pImageData->Unlock();
  2985. }
  2986. return hr;
  2987. }
  2988. HRESULT CPreviewWnd::_SaveAsCmd()
  2989. {
  2990. if (m_pImageData == NULL)
  2991. return S_OK;
  2992. OPENFILENAME ofn = {0};
  2993. TCHAR szOrgFile[MAX_PATH];
  2994. TCHAR szExt[MAX_PATH] = {0};
  2995. PathFromImageData(szOrgFile, ARRAYSIZE(szOrgFile));
  2996. LPTSTR psz = PathFindExtension(szOrgFile);
  2997. StrCpyN(szExt, psz, ARRAYSIZE(szExt));
  2998. TCHAR szFile[MAX_PATH];
  2999. if (!m_fDisableEdit && m_fCanSave && m_pImageData->IsEditable())
  3000. {
  3001. // If we haven't explicitly been told not to and the file is writeable then
  3002. // suggest saving on top of the current image
  3003. PathFromImageData(szFile, ARRAYSIZE(szFile));
  3004. }
  3005. else
  3006. {
  3007. // Otherwise suggest New Image.jpg
  3008. LoadString(_Module.GetModuleInstance(), IDS_NEW_FILENAME, szFile, ARRAYSIZE(szFile));
  3009. }
  3010. CComBSTR bstrTitle;
  3011. bstrTitle.LoadString(IDS_SAVEAS_TITLE);
  3012. ofn.lStructSize = sizeof(ofn);
  3013. PathRemoveExtension(szFile);
  3014. TCHAR szFilter[MAX_PATH] = TEXT("\0");
  3015. ofn.nFilterIndex = _GetFilterStringForSave(szFilter, ARRAYSIZE(szFilter), szExt);
  3016. ofn.lpstrFilter = szFilter;
  3017. ofn.hwndOwner = m_hWnd;
  3018. ofn.lpstrFile = szFile;
  3019. ofn.lpstrTitle = bstrTitle;
  3020. ofn.nMaxFile = MAX_PATH - lstrlen(szExt);
  3021. ofn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_ENABLESIZING;
  3022. ofn.lpstrDefExt = *szExt == TEXT('.') ? szExt + 1: szExt;
  3023. m_fPromptingUser = TRUE;
  3024. BOOL bResult = ::GetSaveFileName(&ofn);
  3025. m_fPromptingUser = FALSE;
  3026. if (bResult != 0)
  3027. {
  3028. m_ctlPreview.CommitAnnotations();
  3029. HRESULT hr = ImageDataSave(szFile, TRUE);
  3030. if (S_OK == hr)
  3031. {
  3032. if (lstrcmpi(szFile, szOrgFile) == 0)
  3033. {
  3034. _UpdateImage();
  3035. ShowFile(szFile, 1);
  3036. m_fDirty = FALSE;
  3037. }
  3038. }
  3039. else if (FAILED(hr))
  3040. {
  3041. // If we failed to save then we are corrupt and need to be reloaded
  3042. // If we were just copying then only show the message
  3043. if (lstrcmpi(szFile, szOrgFile) == 0)
  3044. {
  3045. _UpdateImage();
  3046. ShowFile(szOrgFile, 1, TRUE);
  3047. m_fDirty = FALSE;
  3048. }
  3049. else
  3050. {
  3051. // delete the failed copy
  3052. DeleteFile(szFile);
  3053. }
  3054. CComBSTR bstrMsg, bstrTitle;
  3055. if (bstrMsg.LoadString(IDS_SAVEFAILED_MSGBOX) && bstrTitle.LoadString(IDS_PROJNAME))
  3056. {
  3057. m_fPromptingUser = TRUE;
  3058. MessageBox(bstrMsg, bstrTitle, MB_OK | MB_ICONERROR | MB_APPLMODAL);
  3059. m_fPromptingUser = FALSE;
  3060. return E_FAIL;
  3061. }
  3062. }
  3063. }
  3064. else
  3065. {
  3066. DWORD dwResult = CommDlgExtendedError();
  3067. if (dwResult == FNERR_BUFFERTOOSMALL)
  3068. {
  3069. CComBSTR bstrMsg, bstrTitle;
  3070. if (bstrMsg.LoadString(IDS_NAMETOOLONG_MSGBOX) && bstrTitle.LoadString(IDS_PROJNAME))
  3071. {
  3072. m_fPromptingUser = TRUE;
  3073. MessageBox(bstrMsg, bstrTitle, MB_OK | MB_ICONERROR | MB_APPLMODAL);
  3074. m_fPromptingUser = FALSE;
  3075. }
  3076. }
  3077. return S_FALSE; // User probably cancelled
  3078. }
  3079. return S_OK;
  3080. }
  3081. void CPreviewWnd::_PropertiesCmd()
  3082. {
  3083. if (m_fAnnotating && DPA_GetPtrCount(m_hdpaSelectedAnnotations) == 1)
  3084. {
  3085. CAnnotation* pAnnotation = (CAnnotation*)DPA_GetPtr(m_hdpaSelectedAnnotations, 0);
  3086. if (!pAnnotation->HasWidth() && !pAnnotation->HasTransparent() && !pAnnotation->HasColor() && pAnnotation->HasFont())
  3087. {
  3088. CHOOSEFONT cf = {0};
  3089. LOGFONT lfFont;
  3090. pAnnotation->GetFont(lfFont);
  3091. COLORREF crFont = pAnnotation->GetFontColor();
  3092. cf.lStructSize = sizeof(cf);
  3093. cf.hwndOwner = m_hWnd;
  3094. cf.lpLogFont = &lfFont;
  3095. cf.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_NOVERTFONTS | CF_NOSCRIPTSEL;
  3096. cf.rgbColors = crFont;
  3097. m_fPromptingUser = TRUE;
  3098. BOOL bResult = ::ChooseFont(&cf);
  3099. m_fPromptingUser = FALSE;
  3100. if (bResult)
  3101. {
  3102. crFont = cf.rgbColors;
  3103. lfFont.lfHeight = (lfFont.lfHeight > 0) ? lfFont.lfHeight : -lfFont.lfHeight;
  3104. pAnnotation->SetFont(lfFont);
  3105. pAnnotation->SetFontColor(crFont);
  3106. m_fDirty = TRUE;
  3107. CRegKey Key;
  3108. if (ERROR_SUCCESS != Key.Open(HKEY_CURRENT_USER, REGSTR_SHIMGVW))
  3109. {
  3110. Key.Create(HKEY_CURRENT_USER, REGSTR_SHIMGVW);
  3111. }
  3112. if (Key.m_hKey != NULL)
  3113. {
  3114. Key.SetValue(crFont, REGSTR_TEXTCOLOR);
  3115. ::RegSetValueEx(Key, REGSTR_FONT, 0, REG_BINARY, (LPBYTE)&lfFont, sizeof(lfFont));
  3116. }
  3117. _RefreshSelection();
  3118. }
  3119. }
  3120. else
  3121. {
  3122. m_fPromptingUser = TRUE;
  3123. INT_PTR iResult = DialogBoxParam(_Module.GetModuleInstance(),
  3124. MAKEINTRESOURCE(IDD_ANNOPROPS),
  3125. m_hWnd, _AnnoPropsDlgProc, (LPARAM)this);
  3126. m_fPromptingUser = FALSE;
  3127. }
  3128. }
  3129. else
  3130. {
  3131. // Under these condition the has pressed Ctrl-I to get File Properties
  3132. // So serve them up.
  3133. CComBSTR bstrSummary;
  3134. bstrSummary.LoadString(IDS_SUMMARY);
  3135. _InvokeVerb(TEXT("properties"), bstrSummary);
  3136. }
  3137. }
  3138. HRESULT _VerbMatches(LPCWSTR pszFile, LPCWSTR pszVerb, LPCTSTR pszOurs)
  3139. {
  3140. TCHAR szTemp[MAX_PATH];
  3141. DWORD cch = ARRAYSIZE(szTemp);
  3142. HRESULT hr = AssocQueryString(ASSOCF_VERIFY, ASSOCSTR_COMMAND, pszFile, pszVerb, szTemp, &cch);
  3143. if (SUCCEEDED(hr))
  3144. {
  3145. hr = (StrStrI(szTemp, pszOurs)) ? S_OK : S_FALSE;
  3146. }
  3147. return hr;
  3148. }
  3149. void CPreviewWnd::_OpenCmd()
  3150. {
  3151. HRESULT hr = _SaveIfDirty(TRUE);
  3152. LPCTSTR pszVerb;
  3153. if (S_OK == hr)
  3154. {
  3155. TCHAR szFile[MAX_PATH];
  3156. hr = PathFromImageData(szFile, ARRAYSIZE(szFile));
  3157. if (SUCCEEDED(hr))
  3158. {
  3159. HRESULT hrOpen = _VerbMatches(szFile, L"open", TEXT("shimgvw.dll"));
  3160. HRESULT hrEdit = _VerbMatches(szFile, L"edit", TEXT("mspaint.exe"));
  3161. // if edit is empty, or if edit is mspaint and open is not shimgvw, use the open verb instead
  3162. if (SUCCEEDED(hrEdit))
  3163. {
  3164. if (S_OK == hrEdit && hrOpen == S_FALSE)
  3165. {
  3166. pszVerb = TEXT("open");
  3167. }
  3168. else
  3169. {
  3170. pszVerb = TEXT("edit");
  3171. }
  3172. }
  3173. else if (hrOpen == S_FALSE)
  3174. {
  3175. pszVerb = TEXT("open");
  3176. }
  3177. else
  3178. {
  3179. pszVerb = TEXT("openas");
  3180. }
  3181. hr = _InvokeVerb(pszVerb);
  3182. }
  3183. if (FAILED(hr))
  3184. return;
  3185. // set m_fNoRestore to avoid the rotation confirmation restoration popup-ation
  3186. m_fNoRestore = TRUE;
  3187. // The user had a chance to save but may have said no. Pretend we're not dirty
  3188. m_fDirty = FALSE;
  3189. PostMessage(WM_CLOSE, 0, 0);
  3190. }
  3191. }
  3192. BOOL CPreviewWnd::_CanAnnotate(CDecodeTask * pImageData)
  3193. {
  3194. // If we have an image and its encoder and we haven't been explicitly told not to allow editing
  3195. // and the image is writeable
  3196. if (m_pImageData && m_pImageData->IsEditable() && !m_fDisableEdit && m_fCanSave)
  3197. {
  3198. // then if its a TIFF we can annotate it
  3199. return IsEqualGUID(ImageFormatTIFF, pImageData->_guidFormat);
  3200. }
  3201. return FALSE;
  3202. }
  3203. BOOL CPreviewWnd::_CanCrop(CDecodeTask * pImageData)
  3204. {
  3205. if (m_pImageData != NULL)
  3206. {
  3207. // REVIEW I added this for CyraR as a proof of concept. If we decide to support it
  3208. // we still need to catch all the places where we should save the croppped image and
  3209. // call GDIplus to accomplish the crop.
  3210. #ifdef SUPPORT_CROPPING
  3211. if (S_OK != m_pImageData->IsEditable())
  3212. return FALSE;
  3213. LONG cPages;
  3214. if (S_OK == m_pImageData->GetPageCount(&cPages))
  3215. {
  3216. if (cPages > 1)
  3217. return FALSE;
  3218. }
  3219. return TRUE;
  3220. #endif
  3221. }
  3222. return FALSE;
  3223. }
  3224. // Called whenever the image changes to hide or show the annotation buttons.
  3225. void CPreviewWnd::_SetAnnotatingCommands(BOOL fEnableAnnotations)
  3226. {
  3227. if (CONTROL_MODE != m_dwMode)
  3228. {
  3229. if (fEnableAnnotations)
  3230. {
  3231. m_fCanAnnotate = TRUE;
  3232. m_fAnnotating = FALSE;
  3233. }
  3234. else
  3235. {
  3236. if (m_fAnnotating)
  3237. {
  3238. m_ctlPreview.SetMode(CZoomWnd::MODE_NOACTION);
  3239. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_ZOOMOUTCMD, TBSTATE_ENABLED);
  3240. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_ZOOMINCMD, TBSTATE_ENABLED);
  3241. }
  3242. m_fCanAnnotate = FALSE;
  3243. m_fAnnotating = FALSE;
  3244. }
  3245. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_SELECTCMD, MAKELONG(!m_fCanAnnotate, 0));
  3246. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_ANNOTATESEP, MAKELONG(!m_fCanAnnotate, 0));
  3247. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_FREEHANDCMD, MAKELONG(!m_fCanAnnotate, 0));
  3248. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_HIGHLIGHTCMD, MAKELONG(!m_fCanAnnotate, 0));
  3249. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_LINECMD, MAKELONG(!m_fCanAnnotate, 0));
  3250. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_FRAMECMD, MAKELONG(!m_fCanAnnotate, 0));
  3251. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_RECTCMD, MAKELONG(!m_fCanAnnotate, 0));
  3252. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_TEXTCMD, MAKELONG(!m_fCanAnnotate, 0));
  3253. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_NOTECMD, MAKELONG(!m_fCanAnnotate, 0));
  3254. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_PROPERTIESCMD, MAKELONG(!m_fCanAnnotate, 0));
  3255. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_SELECTCMD, MAKELONG(m_fCanAnnotate, 0));
  3256. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_ANNOTATESEP, MAKELONG(m_fCanAnnotate, 0));
  3257. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_FREEHANDCMD, MAKELONG(m_fCanAnnotate, 0));
  3258. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_HIGHLIGHTCMD, MAKELONG(m_fCanAnnotate, 0));
  3259. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_LINECMD, MAKELONG(m_fCanAnnotate, 0));
  3260. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_FRAMECMD, MAKELONG(m_fCanAnnotate, 0));
  3261. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_RECTCMD, MAKELONG(m_fCanAnnotate, 0));
  3262. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_TEXTCMD, MAKELONG(m_fCanAnnotate, 0));
  3263. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_NOTECMD, MAKELONG(m_fCanAnnotate, 0));
  3264. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_PROPERTIESCMD, MAKELONG(FALSE, 0));
  3265. }
  3266. }
  3267. void CPreviewWnd::_SetCroppingCommands(BOOL fEnableCropping)
  3268. {
  3269. if (CONTROL_MODE != m_dwMode)
  3270. {
  3271. if (fEnableCropping)
  3272. {
  3273. m_fCanCrop = TRUE;
  3274. m_fCropping = FALSE;
  3275. }
  3276. else
  3277. {
  3278. if (m_fCropping)
  3279. {
  3280. m_ctlPreview.SetMode(CZoomWnd::MODE_NOACTION);
  3281. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_ZOOMOUTCMD, TBSTATE_ENABLED);
  3282. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_ZOOMINCMD, TBSTATE_ENABLED);
  3283. }
  3284. m_fCanCrop = FALSE;
  3285. m_fCropping = FALSE;
  3286. }
  3287. m_ctlToolbar.SendMessage(TB_HIDEBUTTON, ID_CROPCMD, MAKELONG(!m_fCanCrop, 0));
  3288. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_CROPCMD, MAKELONG(m_fCanCrop, 0));
  3289. }
  3290. }
  3291. // Called on Toolbar command to fix the state of the other buttons.
  3292. void CPreviewWnd::_UpdateButtons(WORD wID)
  3293. {
  3294. if (CONTROL_MODE != m_dwMode)
  3295. {
  3296. switch (wID)
  3297. {
  3298. case NOBUTTON:
  3299. case ID_ZOOMINCMD:
  3300. case ID_ZOOMOUTCMD:
  3301. case ID_SELECTCMD:
  3302. case ID_CROPCMD:
  3303. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_ZOOMINCMD, TBSTATE_ENABLED);
  3304. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_ZOOMOUTCMD, TBSTATE_ENABLED);
  3305. if (m_fCanAnnotate)
  3306. {
  3307. m_wNewAnnotation = 0;
  3308. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_SELECTCMD, TBSTATE_ENABLED);
  3309. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_FREEHANDCMD, TBSTATE_ENABLED);
  3310. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_HIGHLIGHTCMD, TBSTATE_ENABLED);
  3311. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_LINECMD, TBSTATE_ENABLED);
  3312. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_FRAMECMD, TBSTATE_ENABLED);
  3313. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_RECTCMD, TBSTATE_ENABLED);
  3314. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_TEXTCMD, TBSTATE_ENABLED);
  3315. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_NOTECMD, TBSTATE_ENABLED);
  3316. m_fAnnotating = (wID == ID_SELECTCMD);
  3317. }
  3318. if (m_fCanCrop)
  3319. {
  3320. m_fCropping = (wID == ID_CROPCMD);
  3321. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_CROPCMD, TBSTATE_ENABLED);
  3322. }
  3323. _RefreshSelection(!m_fAnnotating);
  3324. m_ctlToolbar.SendMessage(TB_SETSTATE, wID, TBSTATE_ENABLED|TBSTATE_CHECKED);
  3325. break;
  3326. case ID_FREEHANDCMD:
  3327. case ID_LINECMD:
  3328. case ID_FRAMECMD:
  3329. case ID_RECTCMD:
  3330. case ID_TEXTCMD:
  3331. case ID_NOTECMD:
  3332. case ID_HIGHLIGHTCMD:
  3333. if (m_fCanAnnotate)
  3334. {
  3335. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_ZOOMINCMD, TBSTATE_ENABLED);
  3336. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_ZOOMOUTCMD, TBSTATE_ENABLED);
  3337. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_FREEHANDCMD, TBSTATE_ENABLED);
  3338. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_HIGHLIGHTCMD, TBSTATE_ENABLED);
  3339. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_LINECMD, TBSTATE_ENABLED);
  3340. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_FRAMECMD, TBSTATE_ENABLED);
  3341. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_RECTCMD, TBSTATE_ENABLED);
  3342. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_TEXTCMD, TBSTATE_ENABLED);
  3343. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_NOTECMD, TBSTATE_ENABLED);
  3344. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_SELECTCMD, TBSTATE_ENABLED|TBSTATE_CHECKED);
  3345. m_fAnnotating = TRUE;
  3346. _RefreshSelection(TRUE);
  3347. m_ctlToolbar.SendMessage(TB_SETSTATE, wID, TBSTATE_ENABLED|TBSTATE_CHECKED);
  3348. m_wNewAnnotation = wID;
  3349. }
  3350. break;
  3351. default:
  3352. if (m_fCanAnnotate)
  3353. {
  3354. m_wNewAnnotation = 0;
  3355. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_SELECTCMD, TBSTATE_ENABLED);
  3356. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_FREEHANDCMD, TBSTATE_ENABLED);
  3357. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_HIGHLIGHTCMD, TBSTATE_ENABLED);
  3358. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_LINECMD, TBSTATE_ENABLED);
  3359. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_FRAMECMD, TBSTATE_ENABLED);
  3360. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_RECTCMD, TBSTATE_ENABLED);
  3361. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_TEXTCMD, TBSTATE_ENABLED);
  3362. m_ctlToolbar.SendMessage(TB_SETSTATE, ID_NOTECMD, TBSTATE_ENABLED);
  3363. }
  3364. break;
  3365. }
  3366. }
  3367. }
  3368. void CPreviewWnd::_RefreshSelection(BOOL fDeselect)
  3369. {
  3370. if (m_fCropping)
  3371. _UpdateCroppingSelection();
  3372. _UpdateAnnotatingSelection(fDeselect);
  3373. }
  3374. BOOL CPreviewWnd::_ShouldDisplayAnimations()
  3375. {
  3376. return !::GetSystemMetrics(SM_REMOTESESSION);
  3377. }
  3378. void CPreviewWnd::_UpdateAnnotatingSelection(BOOL fDeselect)
  3379. {
  3380. BOOL bEditing = FALSE;
  3381. if (m_ctlEdit.m_hWnd != NULL)
  3382. {
  3383. if (m_ctlEdit.IsWindowVisible())
  3384. {
  3385. _HideEditing();
  3386. bEditing = TRUE;
  3387. }
  3388. }
  3389. if (DPA_GetPtrCount(m_hdpaSelectedAnnotations) > 0)
  3390. {
  3391. CRect rectUpdate;
  3392. CSelectionTracker tracker;
  3393. _SetupAnnotatingTracker(tracker, bEditing);
  3394. tracker.GetTrueRect(rectUpdate);
  3395. // If we were editing or this was a straight line, we
  3396. // need to get the bounding rect as well
  3397. if (DPA_GetPtrCount(m_hdpaSelectedAnnotations) == 1)
  3398. {
  3399. CRect rect;
  3400. CAnnotation* pAnnotation = (CAnnotation*)DPA_GetPtr(m_hdpaSelectedAnnotations, 0);
  3401. pAnnotation->GetRect(rect);
  3402. m_ctlPreview.GetWindowFromImage((LPPOINT)(LPRECT)rect, 2);
  3403. rectUpdate.UnionRect(rectUpdate, rect);
  3404. }
  3405. m_ctlPreview.InvalidateRect(&rectUpdate);
  3406. if (m_fAnnotating && !fDeselect)
  3407. {
  3408. if (bEditing)
  3409. _StartEditing(FALSE);
  3410. }
  3411. else
  3412. {
  3413. _StopEditing();
  3414. DPA_DeleteAllPtrs(m_hdpaSelectedAnnotations);
  3415. }
  3416. }
  3417. // Disable the properties button if there are 0 or 2 or more annotations selected
  3418. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_PROPERTIESCMD, MAKELONG(DPA_GetPtrCount(m_hdpaSelectedAnnotations) == 1, 0));
  3419. }
  3420. void CPreviewWnd::_UpdateCroppingSelection()
  3421. {
  3422. if (m_fCropping)
  3423. {
  3424. m_ctlPreview.InvalidateRect(NULL);
  3425. }
  3426. }
  3427. void CPreviewWnd::_RemoveAnnotatingSelection()
  3428. {
  3429. // Invalidate current selection and remove annotations
  3430. _UpdateAnnotatingSelection();
  3431. CAnnotationSet* pAnnotations = m_ctlPreview.GetAnnotations();
  3432. for (int i = 0; i < DPA_GetPtrCount(m_hdpaSelectedAnnotations); i++)
  3433. {
  3434. CAnnotation* pAnnotation = (CAnnotation*)DPA_GetPtr(m_hdpaSelectedAnnotations, i);
  3435. pAnnotations->RemoveAnnotation(pAnnotation);
  3436. delete pAnnotation;
  3437. m_fDirty = TRUE;
  3438. }
  3439. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_PROPERTIESCMD, MAKELONG(FALSE, 0));
  3440. DPA_DeleteAllPtrs(m_hdpaSelectedAnnotations);
  3441. }
  3442. void CPreviewWnd::_SetupAnnotatingTracker(CSelectionTracker& tracker, BOOL bEditing)
  3443. {
  3444. CRect rect;
  3445. rect.SetRectEmpty();
  3446. if (!bEditing)
  3447. {
  3448. if (m_ctlEdit.m_hWnd != NULL)
  3449. bEditing = m_ctlEdit.IsWindowVisible();
  3450. }
  3451. if (DPA_GetPtrCount(m_hdpaSelectedAnnotations) > 0)
  3452. {
  3453. CAnnotation* pAnnotation;
  3454. if (DPA_GetPtrCount(m_hdpaSelectedAnnotations) == 1)
  3455. {
  3456. pAnnotation = (CAnnotation*)DPA_GetPtr(m_hdpaSelectedAnnotations, 0);
  3457. // If this is a straight-line annotation then we need to get
  3458. // to the actual points rather than the bounding rect
  3459. if (pAnnotation->GetType() == MT_STRAIGHTLINE)
  3460. {
  3461. CLineMark* pLine = (CLineMark*)pAnnotation;
  3462. pLine->GetPointsRect(rect);
  3463. }
  3464. else
  3465. {
  3466. pAnnotation->GetRect(rect);
  3467. }
  3468. if (bEditing)
  3469. _RotateRect(rect, pAnnotation);
  3470. }
  3471. else
  3472. {
  3473. for (int i = 0; i < DPA_GetPtrCount(m_hdpaSelectedAnnotations); i++)
  3474. {
  3475. CRect rectAnnotation;
  3476. pAnnotation = (CAnnotation*)DPA_GetPtr(m_hdpaSelectedAnnotations, i);
  3477. pAnnotation->GetRect(rectAnnotation);
  3478. rectAnnotation.NormalizeRect();
  3479. rect.UnionRect(rect, rectAnnotation);
  3480. }
  3481. }
  3482. m_ctlPreview.GetWindowFromImage((LPPOINT)(LPRECT)rect, 2);
  3483. }
  3484. tracker.m_rect = rect;
  3485. UINT uStyle = 0;
  3486. if (DPA_GetPtrCount(m_hdpaSelectedAnnotations) > 1)
  3487. {
  3488. uStyle = CSelectionTracker::hatchedBorder;
  3489. }
  3490. else if (DPA_GetPtrCount(m_hdpaSelectedAnnotations) == 1)
  3491. {
  3492. CAnnotation* pAnnotation = (CAnnotation*)DPA_GetPtr(m_hdpaSelectedAnnotations, 0);
  3493. if (pAnnotation->CanResize())
  3494. {
  3495. if (pAnnotation->GetType() == MT_STRAIGHTLINE)
  3496. uStyle = CSelectionTracker::resizeOutside | CSelectionTracker::lineSelection;
  3497. else
  3498. uStyle = CSelectionTracker::solidLine | CSelectionTracker::resizeOutside;
  3499. }
  3500. else
  3501. {
  3502. uStyle = CSelectionTracker::hatchedBorder;
  3503. }
  3504. }
  3505. tracker.m_uStyle = uStyle;
  3506. }
  3507. void CPreviewWnd::_SetupCroppingTracker(CSelectionTracker& tracker)
  3508. {
  3509. if (m_fCropping)
  3510. {
  3511. CRect rect(0, 0, m_ctlPreview.m_cxImage, m_ctlPreview.m_cyImage);
  3512. if (m_rectCropping.IsRectEmpty())
  3513. m_rectCropping = rect;
  3514. rect = m_rectCropping;
  3515. m_ctlPreview.GetWindowFromImage((LPPOINT)(LPRECT)rect, 2);
  3516. tracker.m_rect = rect;
  3517. tracker.m_uStyle = CSelectionTracker::solidLine | CSelectionTracker::resizeOutside;
  3518. }
  3519. }
  3520. BOOL CPreviewWnd::_OnMouseDownForCropping(UINT uMsg, WPARAM wParam, LPARAM lParam)
  3521. {
  3522. if (!m_fCropping)
  3523. return FALSE;
  3524. if (uMsg != WM_LBUTTONDOWN)
  3525. return TRUE;
  3526. CSelectionTracker tracker;
  3527. CPoint point(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  3528. _SetupCroppingTracker(tracker);
  3529. _RefreshSelection();
  3530. if (tracker.HitTest(point) == CSelectionTracker::hitNothing)
  3531. return TRUE;
  3532. if (tracker.Track(m_ctlPreview.m_hWnd, point))
  3533. {
  3534. CRect rectNewPos;
  3535. tracker.GetTrueRect(rectNewPos);
  3536. m_ctlPreview.GetImageFromWindow((LPPOINT)(LPRECT)rectNewPos, 2);
  3537. CRect rectImage(0, 0, m_ctlPreview.m_cxImage, m_ctlPreview.m_cyImage);
  3538. if (rectNewPos.left < rectImage.left)
  3539. m_rectCropping.left = rectImage.left;
  3540. else
  3541. m_rectCropping.left = rectNewPos.left;
  3542. if (rectNewPos.top < rectImage.top)
  3543. m_rectCropping.top = rectImage.top;
  3544. else
  3545. m_rectCropping.top = rectNewPos.top;
  3546. if (rectNewPos.right > rectImage.right)
  3547. m_rectCropping.right = rectImage.right;
  3548. else
  3549. m_rectCropping.right = rectNewPos.right;
  3550. if (rectNewPos.bottom > rectImage.bottom)
  3551. m_rectCropping.bottom = rectImage.bottom;
  3552. else
  3553. m_rectCropping.bottom = rectNewPos.bottom;
  3554. m_fDirty = TRUE;
  3555. }
  3556. _RefreshSelection();
  3557. return TRUE;
  3558. }
  3559. BOOL CPreviewWnd::_OnMouseDownForAnnotating(UINT uMsg, WPARAM wParam, LPARAM lParam)
  3560. {
  3561. if (!m_fAnnotating)
  3562. return FALSE;
  3563. if (uMsg != WM_LBUTTONDOWN)
  3564. return TRUE;
  3565. CRect rect;
  3566. CRect rectImage;
  3567. CPoint point(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  3568. CSelectionTracker tracker;
  3569. m_ctlPreview.GetVisibleImageWindowRect(rectImage);
  3570. if (DPA_GetPtrCount(m_hdpaSelectedAnnotations) == 0)
  3571. {
  3572. _OnMouseDownForAnnotatingHelper(point, rectImage);
  3573. return TRUE;
  3574. }
  3575. _SetupAnnotatingTracker(tracker);
  3576. tracker.GetTrueRect(rect);
  3577. if (tracker.HitTest(point) == CSelectionTracker::hitNothing)
  3578. {
  3579. _RefreshSelection(TRUE);
  3580. _OnMouseDownForAnnotatingHelper(point, rectImage);
  3581. return TRUE;
  3582. }
  3583. if (!tracker.Track(m_ctlPreview.m_hWnd, point))
  3584. {
  3585. _StartEditing();
  3586. return TRUE;
  3587. }
  3588. CRect rectNewPos;
  3589. tracker.GetTrueRect(rectNewPos);
  3590. rect.BottomRight() = rectNewPos.TopLeft();
  3591. m_ctlPreview.GetImageFromWindow((LPPOINT)(LPRECT)rect, 2);
  3592. CSize size = rect.BottomRight() - rect.TopLeft();
  3593. _RefreshSelection();
  3594. if (DPA_GetPtrCount(m_hdpaSelectedAnnotations) > 1)
  3595. {
  3596. if (size.cx == 0 && size.cy == 0)
  3597. return TRUE;
  3598. m_ctlPreview.GetImageFromWindow((LPPOINT)(LPRECT)rectImage, 2);
  3599. rectImage.DeflateRect(5, 5);
  3600. BOOL bValidMove = TRUE;
  3601. for (int i = 0; i < DPA_GetPtrCount(m_hdpaSelectedAnnotations); i++)
  3602. {
  3603. CAnnotation* pAnnotation = (CAnnotation*)DPA_GetPtr(m_hdpaSelectedAnnotations, i);
  3604. pAnnotation->GetRect(rect);
  3605. rect.NormalizeRect();
  3606. rect.OffsetRect(size);
  3607. if (!rectNewPos.IntersectRect(rectImage, rect))
  3608. bValidMove = FALSE;
  3609. }
  3610. if (!bValidMove)
  3611. return TRUE;
  3612. for (int i = 0; i < DPA_GetPtrCount(m_hdpaSelectedAnnotations); i++)
  3613. {
  3614. CAnnotation* pAnnotation = (CAnnotation*)DPA_GetPtr(m_hdpaSelectedAnnotations, i);
  3615. pAnnotation->Move(size);
  3616. }
  3617. }
  3618. else
  3619. {
  3620. CAnnotation* pAnnotation = (CAnnotation*)DPA_GetPtr(m_hdpaSelectedAnnotations, 0);
  3621. if (pAnnotation->CanResize())
  3622. {
  3623. CRect rectTest;
  3624. rect = tracker.m_rect;
  3625. m_ctlPreview.GetImageFromWindow((LPPOINT)(LPRECT)rect, 2);
  3626. rectTest = rect;
  3627. // If the annotation being manipulated is a straight line then the rectangle
  3628. // returned from the tracker could be empty (ie left=right or top=bottom)
  3629. // In this case the IntersectRect test below would fail because windows
  3630. // assumes empty rectangle don't intersect anything.
  3631. if (pAnnotation->GetType() == MT_STRAIGHTLINE)
  3632. {
  3633. if (rectTest.left == rectTest.right)
  3634. rectTest.right++;
  3635. if (rectTest.top == rectTest.bottom)
  3636. rectTest.bottom++;
  3637. }
  3638. rectTest.NormalizeRect();
  3639. m_ctlPreview.GetImageFromWindow((LPPOINT)(LPRECT)rectImage, 2);
  3640. rectImage.DeflateRect(5, 5);
  3641. if (!rectTest.IntersectRect(rectImage, rectTest))
  3642. return TRUE;
  3643. if (m_ctlEdit.m_hWnd != NULL)
  3644. {
  3645. if (m_ctlEdit.IsWindowVisible())
  3646. {
  3647. _RotateRect(rect, pAnnotation);
  3648. }
  3649. }
  3650. // If this is a line then the rect is assumed to be
  3651. // a non-normalized array of points.
  3652. pAnnotation->Resize(rect);
  3653. }
  3654. else
  3655. {
  3656. if (size.cx == 0 && size.cy == 0)
  3657. return TRUE;
  3658. pAnnotation->Move(size);
  3659. }
  3660. }
  3661. m_fDirty = TRUE;
  3662. _RefreshSelection();
  3663. return TRUE;
  3664. }
  3665. void CPreviewWnd::_OnMouseDownForAnnotatingHelper(CPoint ptMouse, CRect rectImage)
  3666. {
  3667. CRect rect;
  3668. CSelectionTracker tracker;
  3669. _SetupAnnotatingTracker(tracker);
  3670. if (m_wNewAnnotation == ID_FREEHANDCMD)
  3671. {
  3672. _CreateFreeHandAnnotation(ptMouse);
  3673. return;
  3674. }
  3675. // If we are creating a line then make sure the tracker has the lineSelection
  3676. // style so we get the appropriate visual feedback.
  3677. if (m_wNewAnnotation == ID_LINECMD)
  3678. {
  3679. tracker.m_uStyle = CSelectionTracker::resizeOutside | CSelectionTracker::lineSelection;
  3680. }
  3681. if (tracker.TrackRubberBand(m_ctlPreview.m_hWnd, ptMouse, TRUE))
  3682. {
  3683. rect = tracker.m_rect;
  3684. rect.NormalizeRect();
  3685. if ((rect.Width() > 10) || (rect.Height() > 10))
  3686. {
  3687. if (m_wNewAnnotation != 0)
  3688. {
  3689. _CreateAnnotation(tracker.m_rect);
  3690. }
  3691. else
  3692. {
  3693. CRect rectTest;
  3694. CRect rectAnnotation;
  3695. CAnnotationSet* pAnnotations = m_ctlPreview.GetAnnotations();
  3696. m_ctlPreview.GetImageFromWindow((LPPOINT)(LPRECT)rect, 2);
  3697. INT_PTR nCount = pAnnotations->GetCount();
  3698. for (INT_PTR i = 0; i < nCount; i++)
  3699. {
  3700. CAnnotation* pAnnotation = pAnnotations->GetAnnotation(i);
  3701. pAnnotation->GetRect(rectAnnotation);
  3702. rectAnnotation.NormalizeRect();
  3703. rectTest.UnionRect(rect, rectAnnotation);
  3704. if (rectTest == rect)
  3705. {
  3706. DPA_AppendPtr(m_hdpaSelectedAnnotations, pAnnotation);
  3707. }
  3708. }
  3709. _RefreshSelection(DPA_GetPtrCount(m_hdpaSelectedAnnotations) == 0);
  3710. }
  3711. }
  3712. }
  3713. else
  3714. {
  3715. if (m_wNewAnnotation == 0)
  3716. {
  3717. if (PtInRect(rectImage, ptMouse))
  3718. {
  3719. m_ctlPreview.GetImageFromWindow(&ptMouse, 1);
  3720. CAnnotationSet* pAnnotations = m_ctlPreview.GetAnnotations();
  3721. INT_PTR nCount = pAnnotations->GetCount();
  3722. // if the user is clicking a single point then
  3723. // we need to search the annotations in zorder
  3724. // from top to bottom
  3725. for (INT_PTR i = nCount - 1; i >= 0; i--)
  3726. {
  3727. CAnnotation* pAnnotation = pAnnotations->GetAnnotation(i);
  3728. pAnnotation->GetRect(rect);
  3729. rect.NormalizeRect();
  3730. if (PtInRect(rect, ptMouse))
  3731. {
  3732. DPA_AppendPtr(m_hdpaSelectedAnnotations, pAnnotation);
  3733. _RefreshSelection();
  3734. return;
  3735. }
  3736. }
  3737. _RefreshSelection(DPA_GetPtrCount(m_hdpaSelectedAnnotations) == 0);
  3738. }
  3739. }
  3740. else
  3741. {
  3742. _UpdateButtons(ID_SELECTCMD);
  3743. }
  3744. }
  3745. }
  3746. void CPreviewWnd::_CreateAnnotation(CRect rect)
  3747. {
  3748. if (m_wNewAnnotation == 0 || m_wNewAnnotation == ID_FREEHANDCMD)
  3749. return;
  3750. ULONG xDPI;
  3751. ULONG yDPI;
  3752. if (!(m_pImageData->GetResolution(&xDPI, &yDPI)))
  3753. return;
  3754. CAnnotation* pAnnotation = NULL;
  3755. switch(m_wNewAnnotation)
  3756. {
  3757. case ID_LINECMD:
  3758. pAnnotation = CAnnotation::CreateAnnotation(MT_STRAIGHTLINE, yDPI);
  3759. break;
  3760. case ID_FRAMECMD:
  3761. pAnnotation = CAnnotation::CreateAnnotation(MT_HOLLOWRECT, yDPI);
  3762. break;
  3763. case ID_RECTCMD:
  3764. pAnnotation = CAnnotation::CreateAnnotation(MT_FILLRECT, yDPI);
  3765. break;
  3766. case ID_TEXTCMD:
  3767. pAnnotation = CAnnotation::CreateAnnotation(MT_TYPEDTEXT, yDPI);
  3768. break;
  3769. case ID_NOTECMD:
  3770. pAnnotation = CAnnotation::CreateAnnotation(MT_ATTACHANOTE, yDPI);
  3771. break;
  3772. case ID_HIGHLIGHTCMD:
  3773. pAnnotation = CAnnotation::CreateAnnotation(MT_FILLRECT, yDPI);
  3774. if (pAnnotation != NULL)
  3775. pAnnotation->SetTransparent(TRUE);
  3776. break;
  3777. }
  3778. if (pAnnotation != NULL)
  3779. {
  3780. COLORREF crBackColor = RGB(255,255,0);
  3781. COLORREF crLineColor = RGB(255,0,0);
  3782. COLORREF crTextColor = RGB(0,0,0);
  3783. LOGFONT lfFont = {12, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, TEXT("Arial") };
  3784. DWORD dwWidth = 1;
  3785. CRegKey Key;
  3786. if (ERROR_SUCCESS == Key.Open(HKEY_CURRENT_USER, REGSTR_SHIMGVW))
  3787. {
  3788. Key.QueryValue(dwWidth, REGSTR_LINEWIDTH);
  3789. Key.QueryValue(crBackColor, REGSTR_BACKCOLOR);
  3790. Key.QueryValue(crLineColor, REGSTR_LINECOLOR);
  3791. Key.QueryValue(crTextColor, REGSTR_TEXTCOLOR);
  3792. DWORD dwType, cbSize;
  3793. cbSize = sizeof(lfFont);
  3794. ::RegQueryValueEx(Key, REGSTR_FONT, NULL, &dwType, (LPBYTE)&lfFont, &cbSize);
  3795. }
  3796. if (m_wNewAnnotation != ID_LINECMD)
  3797. rect.NormalizeRect();
  3798. m_ctlPreview.GetImageFromWindow((LPPOINT)(LPRECT)rect, 2);
  3799. pAnnotation->Resize(rect);
  3800. if (pAnnotation->HasWidth())
  3801. pAnnotation->SetWidth(dwWidth);
  3802. if (pAnnotation->HasColor())
  3803. {
  3804. if (m_wNewAnnotation == ID_LINECMD || m_wNewAnnotation == ID_FRAMECMD)
  3805. pAnnotation->SetColor(crLineColor);
  3806. else
  3807. pAnnotation->SetColor(crBackColor);
  3808. }
  3809. if (pAnnotation->HasFont())
  3810. {
  3811. pAnnotation->SetFont(lfFont);
  3812. pAnnotation->SetFontColor(crTextColor);
  3813. }
  3814. DPA_DeleteAllPtrs(m_hdpaSelectedAnnotations);
  3815. DPA_AppendPtr(m_hdpaSelectedAnnotations, pAnnotation);
  3816. CAnnotationSet* pAnnotations = m_ctlPreview.GetAnnotations();
  3817. pAnnotations->AddAnnotation(pAnnotation);
  3818. m_fDirty = TRUE;
  3819. }
  3820. _UpdateButtons(ID_SELECTCMD);
  3821. }
  3822. void CPreviewWnd::_CreateFreeHandAnnotation(CPoint ptMouse)
  3823. {
  3824. if (m_wNewAnnotation != ID_FREEHANDCMD)
  3825. return;
  3826. // don't handle if capture already set
  3827. if (::GetCapture() != NULL)
  3828. return;
  3829. // set capture to the window which received this message
  3830. ::SetCapture(m_ctlPreview.m_hWnd);
  3831. ASSERT(m_ctlPreview.m_hWnd == ::GetCapture());
  3832. ::UpdateWindow(m_ctlPreview.m_hWnd);
  3833. ULONG xDPI;
  3834. ULONG yDPI;
  3835. if (!(m_pImageData->GetResolution(&xDPI, &yDPI)))
  3836. return;
  3837. CLineMark* pAnnotation = (CLineMark*)CAnnotation::CreateAnnotation(MT_FREEHANDLINE, yDPI);
  3838. if (pAnnotation == NULL)
  3839. return;
  3840. CDSA<POINT> Points;
  3841. Points.Create(256);
  3842. CPoint ptLast = ptMouse;
  3843. m_ctlPreview.GetImageFromWindow(&ptMouse, 1);
  3844. Points.AppendItem(&ptMouse);
  3845. // get DC for drawing
  3846. HDC hdcDraw;
  3847. // otherwise, just use normal DC
  3848. hdcDraw = ::GetDC(m_ctlPreview.m_hWnd);
  3849. ASSERT(hdcDraw != NULL);
  3850. COLORREF crLineColor = RGB(255,0,0);
  3851. DWORD dwWidth = 1;
  3852. CRegKey Key;
  3853. if (ERROR_SUCCESS == Key.Open(HKEY_CURRENT_USER, REGSTR_SHIMGVW))
  3854. {
  3855. Key.QueryValue(dwWidth, REGSTR_LINEWIDTH);
  3856. Key.QueryValue(crLineColor, REGSTR_LINECOLOR);
  3857. }
  3858. CRect rect(0,0,0,dwWidth);
  3859. m_ctlPreview.GetWindowFromImage((LPPOINT)(LPRECT)rect, 2);
  3860. DWORD dwRenderWidth = rect.Height();
  3861. HPEN hpen = ::CreatePen(PS_SOLID, dwRenderWidth, crLineColor);
  3862. HPEN hOld =(HPEN)::SelectObject(hdcDraw, hpen);
  3863. BOOL bCancel=FALSE;
  3864. // get messages until capture lost or cancelled/accepted
  3865. for (;;)
  3866. {
  3867. MSG msg;
  3868. if (!::GetMessage(&msg, NULL, 0, 0))
  3869. {
  3870. ASSERT(FALSE);
  3871. }
  3872. if (m_ctlPreview.m_hWnd != ::GetCapture())
  3873. {
  3874. bCancel = TRUE;
  3875. goto ExitLoop;
  3876. }
  3877. ptMouse.x = GET_X_LPARAM(msg.lParam);
  3878. ptMouse.y = GET_Y_LPARAM(msg.lParam);
  3879. switch (msg.message)
  3880. {
  3881. // handle movement/accept messages
  3882. case WM_LBUTTONUP:
  3883. case WM_MOUSEMOVE:
  3884. ::MoveToEx(hdcDraw, ptLast.x, ptLast.y, NULL);
  3885. ::LineTo(hdcDraw, ptMouse.x, ptMouse.y);
  3886. ptLast = ptMouse;
  3887. m_ctlPreview.GetImageFromWindow(&ptMouse, 1);
  3888. Points.AppendItem(&ptMouse);
  3889. if (msg.message == WM_LBUTTONUP)
  3890. goto ExitLoop;
  3891. break;
  3892. // handle cancel messages
  3893. case WM_KEYDOWN:
  3894. if (msg.wParam != VK_ESCAPE)
  3895. break;
  3896. // else fall through
  3897. case WM_RBUTTONDOWN:
  3898. bCancel = TRUE;
  3899. goto ExitLoop;
  3900. default:
  3901. ::DispatchMessage(&msg);
  3902. break;
  3903. }
  3904. }
  3905. ExitLoop:
  3906. ::SelectObject(hdcDraw, hOld);
  3907. ::DeleteObject(hpen);
  3908. ::ReleaseDC(m_ctlPreview.m_hWnd, hdcDraw);
  3909. ::ReleaseCapture();
  3910. if (!bCancel)
  3911. {
  3912. int nAnnoPoints = Points.GetItemCount();
  3913. POINT* AnnoPoints = new POINT[nAnnoPoints];
  3914. if (AnnoPoints == NULL)
  3915. {
  3916. delete pAnnotation;
  3917. Points.Destroy();
  3918. _UpdateButtons(ID_SELECTCMD);
  3919. return;
  3920. }
  3921. for (int i = 0; i < nAnnoPoints; i++)
  3922. {
  3923. CPoint pt;
  3924. Points.GetItem(i, &pt);
  3925. AnnoPoints[i].x = pt.x;
  3926. AnnoPoints[i].y = pt.y;
  3927. }
  3928. Points.Destroy();
  3929. pAnnotation->SetPoints(AnnoPoints, nAnnoPoints);
  3930. pAnnotation->SetWidth(dwWidth);
  3931. pAnnotation->SetColor(crLineColor);
  3932. DPA_DeleteAllPtrs(m_hdpaSelectedAnnotations);
  3933. DPA_AppendPtr(m_hdpaSelectedAnnotations, pAnnotation);
  3934. CAnnotationSet* pAnnotations = m_ctlPreview.GetAnnotations();
  3935. pAnnotations->AddAnnotation(pAnnotation);
  3936. m_fDirty = TRUE;
  3937. }
  3938. _UpdateButtons(ID_SELECTCMD);
  3939. }
  3940. void CPreviewWnd::_StartEditing(BOOL bUpdateText)
  3941. {
  3942. if (DPA_GetPtrCount(m_hdpaSelectedAnnotations) != 1)
  3943. return;
  3944. CTextAnnotation* pAnnotation = (CTextAnnotation*)DPA_GetPtr(m_hdpaSelectedAnnotations, 0);
  3945. if (!pAnnotation)
  3946. {
  3947. return;
  3948. }
  3949. UINT uType = pAnnotation->GetType();
  3950. if (uType != MT_TYPEDTEXT && uType != MT_FILETEXT && uType != MT_STAMP && uType != MT_ATTACHANOTE)
  3951. return;
  3952. if (m_ctlEdit.m_hWnd == NULL)
  3953. {
  3954. HWND hwndEdit = ::CreateWindow(TEXT("EDIT"), NULL, ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL |
  3955. ES_WANTRETURN | WS_CHILD, 1, 1, 10, 10,
  3956. m_ctlPreview.m_hWnd, (HMENU)1496, NULL, NULL);
  3957. if (hwndEdit == NULL)
  3958. return;
  3959. m_ctlEdit.SubclassWindow(hwndEdit);
  3960. }
  3961. if (bUpdateText)
  3962. {
  3963. CComBSTR bstrText;
  3964. bstrText.Attach(pAnnotation->GetText());
  3965. if (bstrText.m_str != NULL)
  3966. m_ctlEdit.SetWindowText(bstrText);
  3967. else
  3968. m_ctlEdit.SetWindowText(TEXT(""));
  3969. }
  3970. m_ctlEdit.EnableWindow(TRUE);
  3971. LOGFONT lfFont;
  3972. pAnnotation->GetFont(lfFont);
  3973. HDC hdc = ::GetDC(NULL);
  3974. LONG lHeight = pAnnotation->GetFontHeight(hdc);
  3975. ::ReleaseDC(NULL, hdc);
  3976. CRect rect(0,0,0,lHeight);
  3977. m_ctlPreview.GetWindowFromImage((LPPOINT)(LPRECT)rect, 2);
  3978. lfFont.lfHeight = -rect.Height();
  3979. HFONT hNewFont = ::CreateFontIndirect(&lfFont);
  3980. if (hNewFont)
  3981. {
  3982. ::DeleteObject(m_hFont);
  3983. m_hFont = hNewFont;
  3984. m_ctlEdit.SendMessage(WM_SETFONT, (WPARAM)m_hFont, MAKELPARAM(TRUE,0));
  3985. }
  3986. pAnnotation->GetRect(rect);
  3987. _RotateRect(rect, pAnnotation);
  3988. m_ctlPreview.GetWindowFromImage((LPPOINT)(LPRECT)rect, 2);
  3989. m_ctlEdit.SetWindowPos(NULL, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER);
  3990. CSelectionTracker tracker;
  3991. _SetupAnnotatingTracker(tracker, FALSE);
  3992. CRect rectUpdate;
  3993. tracker.GetTrueRect(rectUpdate);
  3994. m_ctlPreview.InvalidateRect(rectUpdate);
  3995. _SetupAnnotatingTracker(tracker, TRUE);
  3996. tracker.GetTrueRect(rectUpdate);
  3997. m_ctlPreview.InvalidateRect(rectUpdate);
  3998. m_ctlEdit.ShowWindow(SW_SHOW);
  3999. m_ctlEdit.SetFocus();
  4000. m_fEditingAnnotation = TRUE;
  4001. }
  4002. void CPreviewWnd::_HideEditing()
  4003. {
  4004. if (m_ctlEdit.m_hWnd == NULL)
  4005. return;
  4006. if (!m_ctlEdit.IsWindowVisible())
  4007. return;
  4008. SetFocus();
  4009. m_ctlEdit.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
  4010. m_ctlEdit.EnableWindow(FALSE);
  4011. }
  4012. void CPreviewWnd::_StopEditing()
  4013. {
  4014. if (m_ctlEdit.m_hWnd == NULL)
  4015. return;
  4016. _HideEditing();
  4017. if (!m_fEditingAnnotation)
  4018. return;
  4019. m_fEditingAnnotation = FALSE;
  4020. if (DPA_GetPtrCount(m_hdpaSelectedAnnotations) != 1)
  4021. return;
  4022. CTextAnnotation* pAnnotation = (CTextAnnotation*)DPA_GetPtr(m_hdpaSelectedAnnotations, 0);
  4023. UINT uType = pAnnotation->GetType();
  4024. if (uType != MT_TYPEDTEXT && uType != MT_FILETEXT && uType != MT_STAMP && uType != MT_ATTACHANOTE)
  4025. return;
  4026. // if the length greater than zero we save it
  4027. // otherwise be blow away the annotation.
  4028. int nLen = m_ctlEdit.GetWindowTextLength();
  4029. if (nLen > 0)
  4030. {
  4031. CComBSTR bstrText(nLen+1);
  4032. m_ctlEdit.GetWindowText(bstrText, nLen+1);
  4033. pAnnotation->SetText(bstrText);
  4034. m_fDirty = TRUE;
  4035. }
  4036. else
  4037. {
  4038. CSelectionTracker tracker;
  4039. _SetupAnnotatingTracker(tracker, TRUE);
  4040. CRect rectUpdate;
  4041. tracker.GetTrueRect(rectUpdate);
  4042. CRect rect;
  4043. pAnnotation->GetRect(rect);
  4044. rectUpdate.UnionRect(rectUpdate, rect);
  4045. DPA_DeleteAllPtrs(m_hdpaSelectedAnnotations);
  4046. CAnnotationSet* pAnnotations = m_ctlPreview.GetAnnotations();
  4047. pAnnotations->RemoveAnnotation(pAnnotation);
  4048. delete pAnnotation;
  4049. m_ctlPreview.InvalidateRect(rectUpdate);
  4050. m_fDirty = TRUE;
  4051. }
  4052. }
  4053. LRESULT CPreviewWnd::OnEditKeyEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled)
  4054. {
  4055. switch (wParam)
  4056. {
  4057. case VK_ESCAPE:
  4058. {
  4059. CSelectionTracker tracker;
  4060. _SetupAnnotatingTracker(tracker);
  4061. CRect rectUpdate;
  4062. tracker.GetTrueRect(rectUpdate);
  4063. _HideEditing();
  4064. m_ctlPreview.InvalidateRect(rectUpdate);
  4065. _RefreshSelection();
  4066. fHandled = TRUE;
  4067. }
  4068. break;
  4069. default:
  4070. fHandled = FALSE;
  4071. break;
  4072. }
  4073. return 0;
  4074. }
  4075. BOOL_PTR CALLBACK CPreviewWnd::_AnnoPropsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  4076. {
  4077. static LOGFONT lfFont;
  4078. static COLORREF crFont;
  4079. static COLORREF crColor;
  4080. CPreviewWnd* pThis;
  4081. switch (msg)
  4082. {
  4083. case WM_INITDIALOG:
  4084. {
  4085. HWND hwndCtl = NULL;
  4086. ::SetWindowLongPtr(hwnd, DWLP_USER, lParam);
  4087. pThis = (CPreviewWnd*)lParam;
  4088. CAnnotation* pAnnotation = (CAnnotation*)DPA_GetPtr(pThis->m_hdpaSelectedAnnotations, 0);
  4089. hwndCtl = ::GetDlgItem(hwnd, IDC_WIDTHTEXT);
  4090. if (!pAnnotation->HasWidth())
  4091. {
  4092. ::EnableWindow(hwndCtl, FALSE);
  4093. ::ShowWindow(hwndCtl, SW_HIDE);
  4094. }
  4095. hwndCtl = ::GetDlgItem(hwnd, IDC_WIDTH);
  4096. if (pAnnotation->HasWidth())
  4097. {
  4098. UINT i = pAnnotation->GetWidth();
  4099. ::SetDlgItemInt(hwnd, IDC_WIDTH, i, FALSE);
  4100. hwndCtl = ::GetDlgItem(hwnd, IDC_SPIN);
  4101. ::SendMessage(hwndCtl, UDM_SETRANGE32, (WPARAM)1, (LPARAM)50);
  4102. ::SendMessage(hwndCtl, UDM_SETPOS32, 0, (LPARAM)i);
  4103. }
  4104. else
  4105. {
  4106. ::EnableWindow(hwndCtl, FALSE);
  4107. ::ShowWindow(hwndCtl, SW_HIDE);
  4108. hwndCtl = ::GetDlgItem(hwnd, IDC_SPIN);
  4109. ::EnableWindow(hwndCtl, FALSE);
  4110. ::ShowWindow(hwndCtl, SW_HIDE);
  4111. }
  4112. hwndCtl = ::GetDlgItem(hwnd, IDC_TRANSPARENT);
  4113. if (pAnnotation->HasTransparent())
  4114. {
  4115. BOOL bTransparent = pAnnotation->GetTransparent();
  4116. ::SendMessage(hwndCtl, BM_SETCHECK, (WPARAM)(bTransparent ? BST_CHECKED : BST_UNCHECKED), 0);
  4117. }
  4118. else
  4119. {
  4120. ::EnableWindow(hwndCtl, FALSE);
  4121. ::ShowWindow(hwndCtl, SW_HIDE);
  4122. }
  4123. if (pAnnotation->HasFont())
  4124. {
  4125. pAnnotation->GetFont(lfFont);
  4126. crFont = pAnnotation->GetFontColor();
  4127. }
  4128. else
  4129. {
  4130. hwndCtl = ::GetDlgItem(hwnd, IDC_FONT);
  4131. ::EnableWindow(hwndCtl, FALSE);
  4132. ::ShowWindow(hwndCtl, SW_HIDE);
  4133. }
  4134. if (pAnnotation->HasColor())
  4135. {
  4136. crColor = pAnnotation->GetColor();
  4137. }
  4138. else
  4139. {
  4140. hwndCtl = ::GetDlgItem(hwnd, IDC_COLOR);
  4141. ::EnableWindow(hwndCtl, FALSE);
  4142. ::ShowWindow(hwndCtl, SW_HIDE);
  4143. }
  4144. }
  4145. break;
  4146. case WM_COMMAND:
  4147. pThis = (CPreviewWnd*)::GetWindowLongPtr(hwnd, DWLP_USER);
  4148. switch (wParam)
  4149. {
  4150. case IDOK:
  4151. pThis->_RefreshSelection();
  4152. {
  4153. HWND hwndCtl = NULL;
  4154. CAnnotation* pAnnotation = (CAnnotation*)DPA_GetPtr(pThis->m_hdpaSelectedAnnotations, 0);
  4155. CRegKey Key;
  4156. if (ERROR_SUCCESS != Key.Open(HKEY_CURRENT_USER, REGSTR_SHIMGVW))
  4157. {
  4158. Key.Create(HKEY_CURRENT_USER, REGSTR_SHIMGVW);
  4159. }
  4160. if (pAnnotation->HasWidth())
  4161. {
  4162. UINT uWidth = ::GetDlgItemInt(hwnd, IDC_WIDTH, NULL, FALSE);
  4163. if (uWidth > 50 || uWidth < 1)
  4164. {
  4165. CComBSTR bstrMsg, bstrTitle;
  4166. if (bstrMsg.LoadString(IDS_WIDTHBAD_MSGBOX) && bstrTitle.LoadString(IDS_PROJNAME))
  4167. {
  4168. ::MessageBox(hwnd, bstrMsg, bstrTitle, MB_OK | MB_ICONERROR | MB_APPLMODAL);
  4169. }
  4170. ::SetDlgItemInt(hwnd, IDC_WIDTH, 50, FALSE);
  4171. return FALSE;
  4172. }
  4173. pAnnotation->SetWidth(uWidth);
  4174. if (Key.m_hKey != NULL)
  4175. {
  4176. Key.SetValue(uWidth, REGSTR_LINEWIDTH);
  4177. }
  4178. }
  4179. if (pAnnotation->HasTransparent())
  4180. {
  4181. hwndCtl = ::GetDlgItem(hwnd, IDC_TRANSPARENT);
  4182. BOOL bTransparent = FALSE;
  4183. if (::SendMessage(hwndCtl, BM_GETCHECK, 0, 0) == BST_CHECKED)
  4184. bTransparent = TRUE;
  4185. pAnnotation->SetTransparent(bTransparent);
  4186. }
  4187. if (pAnnotation->HasFont())
  4188. {
  4189. lfFont.lfHeight = (lfFont.lfHeight > 0) ? lfFont.lfHeight : -lfFont.lfHeight;
  4190. pAnnotation->SetFont(lfFont);
  4191. pAnnotation->SetFontColor(crFont);
  4192. if (Key.m_hKey != NULL)
  4193. {
  4194. Key.SetValue(crFont, REGSTR_TEXTCOLOR);
  4195. ::RegSetValueEx(Key, REGSTR_FONT, 0, REG_BINARY, (LPBYTE)&lfFont, sizeof(lfFont));
  4196. }
  4197. }
  4198. if (pAnnotation->HasColor())
  4199. {
  4200. pAnnotation->SetColor(crColor);
  4201. UINT uType = pAnnotation->GetType();
  4202. if (Key.m_hKey != NULL)
  4203. {
  4204. if (uType == MT_STRAIGHTLINE || uType == MT_FREEHANDLINE || uType == MT_HOLLOWRECT)
  4205. Key.SetValue(crColor, REGSTR_LINECOLOR);
  4206. else
  4207. Key.SetValue(crColor, REGSTR_BACKCOLOR);
  4208. }
  4209. }
  4210. }
  4211. pThis->m_fDirty = TRUE;
  4212. pThis->_RefreshSelection();
  4213. EndDialog(hwnd, wParam);
  4214. return FALSE;
  4215. case IDCANCEL:
  4216. EndDialog(hwnd, wParam);
  4217. return FALSE;
  4218. case IDC_FONT:
  4219. {
  4220. CHOOSEFONT cf = {0};
  4221. LOGFONT lf;
  4222. lf = lfFont;
  4223. cf.lStructSize = sizeof(cf);
  4224. cf.hwndOwner = hwnd;
  4225. cf.lpLogFont = &lf;
  4226. cf.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_NOVERTFONTS | CF_NOSCRIPTSEL;
  4227. cf.rgbColors = crFont;
  4228. if (::ChooseFont(&cf))
  4229. {
  4230. CopyMemory (&lfFont, &lf, sizeof(lf));
  4231. crFont = cf.rgbColors;
  4232. }
  4233. }
  4234. return FALSE;
  4235. case IDC_COLOR:
  4236. {
  4237. CHOOSECOLOR cc = {0};
  4238. cc.lStructSize = sizeof(cc);
  4239. cc.hwndOwner = hwnd;
  4240. cc.rgbResult = crColor;
  4241. cc.lpCustColors = g_crCustomColors;
  4242. cc.Flags = CC_RGBINIT | CC_SOLIDCOLOR;
  4243. if (::ChooseColor(&cc))
  4244. {
  4245. crColor = cc.rgbResult;
  4246. }
  4247. }
  4248. return FALSE;
  4249. default:
  4250. break;
  4251. }
  4252. break;
  4253. default:
  4254. return FALSE;
  4255. }
  4256. return TRUE;
  4257. }
  4258. BOOL CPreviewWnd::_TrySetImage()
  4259. {
  4260. BOOL fRet = FALSE;
  4261. if (m_pNextImageData && m_pNextImageData->_iItem == m_iCurSlide)
  4262. {
  4263. if (SUCCEEDED(m_pNextImageData->_hr))
  4264. {
  4265. m_fCanSave = !m_pNextImageData->_fIsReadOnly;
  4266. // update the toolbar state, our child windows, and our sibling windows
  4267. _SetNewImage(m_pNextImageData);
  4268. ATOMICRELEASE(m_pNextImageData);
  4269. if (m_pImageData->IsAnimated() && _ShouldDisplayAnimations())
  4270. {
  4271. // start the animation timer
  4272. SetTimer(TIMER_ANIMATION, m_pImageData->GetDelay());
  4273. }
  4274. // Notify anyone listening to our events that a preview has been completed
  4275. // we only fire this upon success
  4276. if (m_pEvents)
  4277. {
  4278. m_pEvents->OnPreviewReady();
  4279. }
  4280. fRet = TRUE;
  4281. }
  4282. else
  4283. {
  4284. // update the status to display an error message. This will also update the toolbar state.
  4285. StatusUpdate(IDS_LOADFAILED);
  4286. //
  4287. // We can't remove the item from the array because the user might try to delete it while
  4288. // the "load failed" string is still visible for it.
  4289. // even though the item failed to decode we must wait on the "Load Failed" state when we are in
  4290. // windowed mode, otherwise "open with..." is broken when you open a corrupted image or non-image.
  4291. // In slideshow mode we could simply skip to the next image.
  4292. if (m_pEvents)
  4293. m_pEvents->OnError();
  4294. }
  4295. }
  4296. return fRet;
  4297. }
  4298. LRESULT CPreviewWnd::IV_OnSetImageData(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled)
  4299. {
  4300. CDecodeTask * pData = (CDecodeTask *)wParam;
  4301. ATOMICRELEASE(m_pNextImageData);
  4302. m_pNextImageData = pData;
  4303. if (m_pNextImageData && m_iDecodingNextImage == m_pNextImageData->_iItem)
  4304. {
  4305. // We have finished decoding now, let's remember this.
  4306. m_iDecodingNextImage = -1;
  4307. // Let 's prepare the drawing now. This draws in the back buffer. Don't start this if we want to see
  4308. // the image now, as it would delay things.
  4309. if (SUCCEEDED(m_pNextImageData->_hr) && m_pNextImageData->_iItem != m_iCurSlide)
  4310. {
  4311. m_ctlPreview.PrepareImageData(m_pNextImageData);
  4312. }
  4313. }
  4314. _TrySetImage();
  4315. return TRUE;
  4316. }
  4317. // Creation of the image data is asynchronous. When our worker thread is done decoding
  4318. // an image it posts a IV_SETIMAGEDATA message with the image data object. As a result,
  4319. // we must flush these messages when the window is destroyed to prevent leaking any handles.
  4320. void CPreviewWnd::FlushBitmapMessages()
  4321. {
  4322. // Pass TRUE to wait for task to be removed before peeking out its messages
  4323. // Otherwise, if the task is in the middle of running, our PeekMessage won't
  4324. // see anything and we will return. Then the task will finish, post its message,
  4325. // and leak the data since we're not around to receive it.
  4326. TASKOWNERID toid;
  4327. GetTaskIDFromMode(GTIDFM_DECODE, m_dwMode, &toid);
  4328. if (m_pTaskScheduler)
  4329. {
  4330. m_pTaskScheduler->RemoveTasks(toid, ITSAT_DEFAULT_LPARAM, TRUE);
  4331. }
  4332. // if we were waiting for another image frame to be generated then cut it out, we don't care about that anymore
  4333. // if we have an animation timer running then kill it and remove any WM_TIMER messages
  4334. KillTimer(TIMER_ANIMATION);
  4335. KillTimer(TIMER_SLIDESHOW);
  4336. MSG msg;
  4337. while (PeekMessage(&msg, m_hWnd, WM_TIMER, WM_TIMER, PM_REMOVE))
  4338. {
  4339. // NTRAID#NTBUG9-359356-2001/04/05-seank
  4340. // If the queue is empty when PeekMessage is called and we have already
  4341. // Posted a quit message then PeekMessage will return a WM_QUIT message
  4342. // regardless of the filter min and max and subsequent calls to
  4343. // GetMessage will hang indefinitely see SEANK or JASONSCH for more
  4344. // info.
  4345. if (msg.message == WM_QUIT)
  4346. {
  4347. PostQuitMessage(0);
  4348. return;
  4349. }
  4350. }
  4351. // make sure any posted messages get flushed and we free the associated data
  4352. while (PeekMessage(&msg, m_hWnd, IV_SETIMAGEDATA, IV_SETIMAGEDATA, PM_REMOVE))
  4353. {
  4354. // NTRAID#NTBUG9-359356-2001/04/05-seank
  4355. // If the queue is empty when PeekMessage is called and we have already
  4356. // Posted a quit message then PeekMessage will return a WM_QUIT message
  4357. // regardless of the filter min and max and subsequent calls to
  4358. // GetMessage will hang indefinitely see SEANK or JASONSCH for more
  4359. // info.
  4360. if (msg.message == WM_QUIT)
  4361. {
  4362. PostQuitMessage(0);
  4363. return;
  4364. }
  4365. CDecodeTask * pData = (CDecodeTask *)msg.wParam;
  4366. ATOMICRELEASE(pData);
  4367. }
  4368. }
  4369. LRESULT CPreviewWnd::OnCopyData(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&)
  4370. {
  4371. // We can get into a situation where we are still trying to preview
  4372. // the previous oncopydata because the previous window to that was a
  4373. // tiff that was being annotated and is prompting you to save. In this
  4374. // case throw away any future data
  4375. if (_pdtobj != NULL || m_fPromptingUser)
  4376. return TRUE;
  4377. COPYDATASTRUCT *pcds = (COPYDATASTRUCT*)lParam;
  4378. if (pcds)
  4379. {
  4380. HRESULT hr = E_FAIL;
  4381. switch (pcds->dwData)
  4382. {
  4383. case COPYDATATYPE_DATAOBJECT:
  4384. {
  4385. IStream *pstm;
  4386. if (SUCCEEDED(CreateStreamOnHGlobal(NULL, TRUE, &pstm)))
  4387. {
  4388. const LARGE_INTEGER li = {0, 0};
  4389. pstm->Write(pcds->lpData, pcds->cbData, NULL);
  4390. pstm->Seek(li, STREAM_SEEK_SET, NULL);
  4391. // unfortunaly we can not program the data object here as we are in a
  4392. // SendMessage() and any calls made on the data object will fail because
  4393. // of this. instead we grab a ref to the data object and set a timer
  4394. // so we can handle this once we have unwound from the send.
  4395. hr = CoUnmarshalInterface(pstm, IID_PPV_ARG(IDataObject, &_pdtobj));
  4396. pstm->Release();
  4397. }
  4398. }
  4399. break;
  4400. case COPYDATATYPE_FILENAME:
  4401. {
  4402. hr = GetUIObjectFromPath((LPCTSTR)pcds->lpData, IID_PPV_ARG(IDataObject, &_pdtobj));
  4403. }
  4404. break;
  4405. }
  4406. // unfortunaly we can not program the data object here as we are in a
  4407. // SendMessage() and any calls made on the data object will fail because
  4408. // of this. instead we grab a ref to the data object and set a timer
  4409. // so we can handle this once we have unwound from the send.
  4410. if (SUCCEEDED(hr))
  4411. {
  4412. SetTimer(TIMER_DATAOBJECT, 100); // do the real work here
  4413. }
  4414. }
  4415. return TRUE;
  4416. }
  4417. DWORD MakeFilterFromCodecs(LPTSTR szFilter, size_t cbFilter, UINT nCodecs, ImageCodecInfo *pCodecs, LPTSTR szExt, BOOL fExcludeTIFF)
  4418. {
  4419. size_t nOffset = 0;
  4420. DWORD dwRet = 1;
  4421. for (UINT i = 0; i < nCodecs && nOffset < cbFilter - 1; i++)
  4422. {
  4423. if (fExcludeTIFF && StrStrI(pCodecs->FilenameExtension, L"*.tif"))
  4424. {
  4425. continue;
  4426. }
  4427. // make sure there's space for nulls between strings and 2 at the end
  4428. if (4+lstrlen(pCodecs->FormatDescription) + lstrlen(pCodecs->FilenameExtension) + nOffset < cbFilter)
  4429. {
  4430. StrCpyN(szFilter+nOffset,pCodecs->FormatDescription, cbFilter -(nOffset + 1));
  4431. nOffset+=lstrlen(pCodecs->FormatDescription)+1;
  4432. StrCpyN(szFilter+nOffset,pCodecs->FilenameExtension, cbFilter -(nOffset + 1));
  4433. nOffset+=lstrlen(pCodecs->FilenameExtension)+1;
  4434. if (StrStrI(pCodecs->FilenameExtension, szExt))
  4435. {
  4436. dwRet = i + 1;
  4437. }
  4438. pCodecs++;
  4439. }
  4440. }
  4441. szFilter[nOffset] = 0;
  4442. return dwRet;
  4443. }
  4444. DWORD CPreviewWnd::_GetFilterStringForSave(LPTSTR szFilter, size_t cbFilter, LPTSTR szExt)
  4445. {
  4446. UINT nCodecs = 0;
  4447. UINT cbCodecs = 0;
  4448. BYTE *pData;
  4449. GetImageEncodersSize (&nCodecs, &cbCodecs);
  4450. DWORD dwRet = 1; // ofn.nFilterIndex is 1-based
  4451. if (cbCodecs)
  4452. {
  4453. pData = new BYTE[cbCodecs];
  4454. if (pData)
  4455. {
  4456. ImageCodecInfo *pCodecs = reinterpret_cast<ImageCodecInfo*>(pData);
  4457. if (Ok == GetImageEncoders (nCodecs, cbCodecs, pCodecs))
  4458. {
  4459. dwRet = MakeFilterFromCodecs(szFilter, cbFilter, nCodecs, pCodecs, szExt, m_pImageData->IsExtendedPixelFmt());
  4460. }
  4461. delete [] pData;
  4462. }
  4463. }
  4464. return dwRet;
  4465. }
  4466. HRESULT CPreviewWnd::SaveAs(BSTR bstrPath)
  4467. {
  4468. HRESULT hr = E_FAIL;
  4469. if (m_pImageData && m_pImageFactory)
  4470. {
  4471. IShellImageData * pSID;
  4472. hr = m_pImageData->Lock(&pSID);
  4473. if (SUCCEEDED(hr))
  4474. {
  4475. GUID guidFmt;
  4476. if (SUCCEEDED(m_pImageFactory->GetDataFormatFromPath(bstrPath, &guidFmt)))
  4477. {
  4478. IPropertyBag *pbagEnc;
  4479. hr = SHCreatePropertyBagOnMemory(STGM_READWRITE, IID_PPV_ARG(IPropertyBag, &pbagEnc));
  4480. if (SUCCEEDED(hr))
  4481. {
  4482. VARIANT var;
  4483. hr = InitVariantFromGUID(&var, guidFmt);
  4484. if (SUCCEEDED(hr))
  4485. {
  4486. hr = pbagEnc->Write(SHIMGKEY_RAWFORMAT, &var);
  4487. if (SUCCEEDED(hr))
  4488. {
  4489. hr = pSID->SetEncoderParams(pbagEnc);
  4490. }
  4491. VariantClear(&var);
  4492. }
  4493. pbagEnc->Release();
  4494. }
  4495. }
  4496. IPersistFile *ppf;
  4497. hr = pSID->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
  4498. if (SUCCEEDED(hr))
  4499. {
  4500. hr = ppf->Save(bstrPath, TRUE);
  4501. ppf->Release();
  4502. }
  4503. m_pImageData->Unlock();
  4504. }
  4505. }
  4506. return hr;
  4507. }
  4508. BOOL CPreviewWnd::_IsImageFile(LPCTSTR pszFile)
  4509. {
  4510. BOOL bRet = FALSE;
  4511. if (m_pici || _BuildDecoderList())
  4512. {
  4513. bRet = (-1 != FindInDecoderList(m_pici, m_cDecoders, pszFile));
  4514. }
  4515. return bRet;
  4516. }
  4517. BOOL CPreviewWnd::_BuildDecoderList()
  4518. {
  4519. UINT cb;
  4520. BOOL bRet = FALSE;
  4521. if (Ok == GetImageDecodersSize(&m_cDecoders, &cb))
  4522. {
  4523. m_pici = (ImageCodecInfo*)LocalAlloc(LPTR, cb);
  4524. if (m_pici)
  4525. {
  4526. if (Ok != GetImageDecoders(m_cDecoders, cb, m_pici))
  4527. {
  4528. LocalFree(m_pici);
  4529. m_pici = NULL;
  4530. }
  4531. else
  4532. {
  4533. bRet = TRUE;
  4534. }
  4535. }
  4536. }
  4537. return bRet;
  4538. }
  4539. void CPreviewWnd::OpenFileList(HWND hwnd, IDataObject *pdtobj)
  4540. {
  4541. if (NULL == hwnd)
  4542. hwnd = m_hWnd;
  4543. IStream *pstm;
  4544. HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &pstm);
  4545. if (SUCCEEDED(hr))
  4546. {
  4547. hr = CoMarshalInterface(pstm, IID_IDataObject, pdtobj, MSHCTX_NOSHAREDMEM, NULL, MSHLFLAGS_NORMAL);
  4548. if (SUCCEEDED(hr))
  4549. {
  4550. HGLOBAL hGlobal;
  4551. hr = GetHGlobalFromStream(pstm, &hGlobal);
  4552. if (SUCCEEDED(hr))
  4553. {
  4554. COPYDATASTRUCT cds = {0};
  4555. cds.dwData = COPYDATATYPE_DATAOBJECT;
  4556. cds.cbData = (DWORD)GlobalSize(hGlobal);
  4557. cds.lpData = GlobalLock(hGlobal);
  4558. SendMessage(hwnd, WM_COPYDATA, NULL, (LPARAM)&cds);
  4559. SetForegroundWindow(hwnd);
  4560. GlobalUnlock(hGlobal);
  4561. }
  4562. }
  4563. pstm->Release();
  4564. }
  4565. }
  4566. void CPreviewWnd::OpenFile(HWND hwnd, LPCTSTR pszFile)
  4567. {
  4568. if (NULL == hwnd)
  4569. hwnd = m_hWnd;
  4570. COPYDATASTRUCT cds = {0};
  4571. cds.dwData = COPYDATATYPE_FILENAME;
  4572. cds.cbData = (lstrlen(pszFile)+1)*sizeof(TCHAR);
  4573. cds.lpData = (void*)pszFile;
  4574. SendMessage(hwnd, WM_COPYDATA, NULL, (LPARAM)&cds);
  4575. SetForegroundWindow(hwnd);
  4576. }
  4577. // returns:
  4578. // TRUE window was re-used
  4579. BOOL CPreviewWnd::TryWindowReuse(IDataObject *pdtobj)
  4580. {
  4581. BOOL bRet = FALSE;
  4582. HWND hwnd = FindWindow(TEXT("ShImgVw:CPreviewWnd"), NULL);
  4583. if (hwnd)
  4584. {
  4585. // window reuse can't always work because shortcuts are launched on a thread that
  4586. // is too short lived to support the marshalled IDataObject given to us via WM_COPYDATA
  4587. // For now we'll try to close an existing window and open a new one.
  4588. ::PostMessage(hwnd, WM_CLOSE, 0, 0);
  4589. }
  4590. return bRet;
  4591. }
  4592. // returns:
  4593. // TRUE window was re-used
  4594. BOOL CPreviewWnd::TryWindowReuse(LPCTSTR pszFileName)
  4595. {
  4596. BOOL bRet = FALSE;
  4597. HWND hwnd = FindWindow(TEXT("ShImgVw:CPreviewWnd"), NULL);
  4598. if (hwnd)
  4599. {
  4600. DWORD_PTR dwResult = FALSE;
  4601. SendMessageTimeout(hwnd, IV_ISAVAILABLE, 0, 0, SMTO_ABORTIFHUNG | SMTO_BLOCK, 1000, &dwResult);
  4602. if (dwResult)
  4603. {
  4604. OpenFile(hwnd, pszFileName);
  4605. bRet = TRUE;
  4606. }
  4607. }
  4608. return bRet;
  4609. }
  4610. STDMETHODIMP CPreviewWnd::QueryInterface(REFIID riid, void **ppv)
  4611. {
  4612. static const QITAB qit[] =
  4613. {
  4614. QITABENT(CPreviewWnd, IDropTarget),
  4615. QITABENT(CPreviewWnd, INamespaceWalkCB),
  4616. QITABENT(CPreviewWnd, IServiceProvider),
  4617. QITABENT(CPreviewWnd, IImgCmdTarget),
  4618. { 0 },
  4619. };
  4620. return QISearch(this, qit, riid, ppv);
  4621. }
  4622. STDMETHODIMP_(ULONG) CPreviewWnd::AddRef()
  4623. {
  4624. return 3;
  4625. }
  4626. STDMETHODIMP_(ULONG) CPreviewWnd::Release()
  4627. {
  4628. return 2;
  4629. }
  4630. // INamespaceWalkCB
  4631. STDMETHODIMP CPreviewWnd::FoundItem(IShellFolder *psf, LPCITEMIDLIST pidl)
  4632. {
  4633. HRESULT hr = S_FALSE;
  4634. if (m_fFirstItem && (WINDOW_MODE == m_dwMode))
  4635. {
  4636. // REVIEW: Do this in other modes too?
  4637. StatusUpdate(IDS_LOADING);
  4638. m_fFirstItem = FALSE;
  4639. hr = S_OK;
  4640. }
  4641. else
  4642. {
  4643. TCHAR szName[MAX_PATH];
  4644. DisplayNameOf(psf, pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, szName, ARRAYSIZE(szName));
  4645. if (_IsImageFile(szName))
  4646. {
  4647. hr = S_OK;
  4648. }
  4649. }
  4650. if (WINDOW_MODE == m_dwMode)
  4651. {
  4652. MSG msg;
  4653. while (PeekMessage(&msg, m_hWnd, 0, 0, PM_REMOVE))
  4654. {
  4655. TranslateMessage(&msg);
  4656. DispatchMessage(&msg);
  4657. }
  4658. }
  4659. return hr;
  4660. }
  4661. STDMETHODIMP CPreviewWnd::EnterFolder(IShellFolder *psf, LPCITEMIDLIST pidl)
  4662. {
  4663. return S_OK;
  4664. }
  4665. STDMETHODIMP CPreviewWnd::LeaveFolder(IShellFolder *psf, LPCITEMIDLIST pidl)
  4666. {
  4667. return S_OK;
  4668. }
  4669. // IDropTarget
  4670. STDMETHODIMP CPreviewWnd::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  4671. {
  4672. m_dwEffect = DROPEFFECT_NONE;
  4673. //
  4674. // We only support CFSTR_SHELLIDLIST and CF_HDROP
  4675. //
  4676. static CLIPFORMAT cfidlist = 0;
  4677. if (!cfidlist)
  4678. {
  4679. cfidlist = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_SHELLIDLIST);
  4680. }
  4681. FORMATETC fmt = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  4682. if (SUCCEEDED(pdtobj->QueryGetData(&fmt)))
  4683. {
  4684. m_dwEffect = DROPEFFECT_COPY;
  4685. }
  4686. else
  4687. {
  4688. fmt.cfFormat = cfidlist;
  4689. if (SUCCEEDED(pdtobj->QueryGetData(&fmt)))
  4690. {
  4691. m_dwEffect = DROPEFFECT_COPY;
  4692. }
  4693. }
  4694. *pdwEffect &= m_dwEffect;
  4695. return S_OK;
  4696. }
  4697. STDMETHODIMP CPreviewWnd::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  4698. {
  4699. *pdwEffect &= m_dwEffect;
  4700. return S_OK;
  4701. }
  4702. STDMETHODIMP CPreviewWnd::DragLeave()
  4703. {
  4704. m_dwEffect = DROPEFFECT_NONE;
  4705. return S_OK;
  4706. }
  4707. STDMETHODIMP CPreviewWnd::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  4708. {
  4709. if (m_dwEffect != DROPEFFECT_NONE)
  4710. {
  4711. PreviewItemsFromUnk(pdtobj);
  4712. }
  4713. *pdwEffect &= m_dwEffect;
  4714. return S_OK;
  4715. }
  4716. //////////////////////////////////////////////////////////////////////////////////////////////////////
  4717. //
  4718. // IServiceProvider
  4719. //
  4720. //////////////////////////////////////////////////////////////////////////////////////////////////////
  4721. STDMETHODIMP CPreviewWnd::QueryService(REFGUID guidService, REFIID riid, void **ppv)
  4722. {
  4723. if (SID_SImageView == guidService)
  4724. {
  4725. return QueryInterface(riid, ppv);
  4726. }
  4727. else if (m_punkSite)
  4728. {
  4729. return IUnknown_QueryService(m_punkSite, guidService, riid, ppv);
  4730. }
  4731. return E_FAIL;
  4732. }
  4733. //////////////////////////////////////////////////////////////////////////////////////////////////////
  4734. //
  4735. // IImgCmdTarget
  4736. //
  4737. //////////////////////////////////////////////////////////////////////////////////////////////////////
  4738. STDMETHODIMP CPreviewWnd::GetMode(DWORD * pdw)
  4739. {
  4740. *pdw = m_dwMode;
  4741. return S_OK;
  4742. }
  4743. STDMETHODIMP CPreviewWnd::GetPageFlags(DWORD * pdw)
  4744. {
  4745. *pdw = m_dwMultiPageMode;
  4746. return S_OK;
  4747. }
  4748. STDMETHODIMP CPreviewWnd::ZoomIn()
  4749. {
  4750. if (SLIDESHOW_MODE == m_dwMode)
  4751. {
  4752. m_ctlPreview.ZoomIn();
  4753. }
  4754. else
  4755. {
  4756. m_ctlPreview.SetMode(CZoomWnd::MODE_ZOOMIN);
  4757. m_ctlPreview.ZoomIn();
  4758. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_ACTUALSIZECMD, MAKELONG(TRUE, 0));
  4759. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_BESTFITCMD, MAKELONG(TRUE, 0));
  4760. _UpdateButtons(ID_ZOOMINCMD);
  4761. }
  4762. return S_OK;
  4763. }
  4764. STDMETHODIMP CPreviewWnd::ZoomOut()
  4765. {
  4766. if (SLIDESHOW_MODE == m_dwMode)
  4767. {
  4768. m_ctlPreview.ZoomOut();
  4769. }
  4770. else
  4771. {
  4772. m_ctlPreview.SetMode(CZoomWnd::MODE_ZOOMOUT);
  4773. m_ctlPreview.ZoomOut();
  4774. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_ACTUALSIZECMD, MAKELONG(TRUE, 0));
  4775. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_BESTFITCMD, MAKELONG(!m_ctlPreview.IsBestFit(), 0));
  4776. _UpdateButtons(ID_ZOOMOUTCMD);
  4777. }
  4778. return S_OK;
  4779. }
  4780. STDMETHODIMP CPreviewWnd::ActualSize()
  4781. {
  4782. _RefreshSelection(FALSE);
  4783. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_ACTUALSIZECMD, MAKELONG(FALSE, 0));
  4784. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_BESTFITCMD, MAKELONG(TRUE, 0));
  4785. m_ctlPreview.ActualSize();
  4786. if (m_pEvents)
  4787. {
  4788. m_pEvents->OnActualSizePress();
  4789. }
  4790. return S_OK;
  4791. }
  4792. STDMETHODIMP CPreviewWnd::BestFit()
  4793. {
  4794. _RefreshSelection(FALSE);
  4795. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_ACTUALSIZECMD, MAKELONG(TRUE, 0));
  4796. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_BESTFITCMD, MAKELONG(FALSE, 0));
  4797. m_ctlPreview.BestFit();
  4798. if (m_pEvents)
  4799. {
  4800. m_pEvents->OnBestFitPress();
  4801. }
  4802. return S_OK;
  4803. }
  4804. STDMETHODIMP CPreviewWnd::Rotate(DWORD dwAngle)
  4805. {
  4806. WORD wRotate;
  4807. switch (dwAngle)
  4808. {
  4809. case 90:
  4810. wRotate = ID_ROTATE90CMD;
  4811. break;
  4812. case 270:
  4813. wRotate = ID_ROTATE270CMD;
  4814. break;
  4815. default:
  4816. return E_INVALIDARG;
  4817. }
  4818. // If we don't have an image yet, there is nothing for us to do.
  4819. // Note: The keyboard accelerator will hit this path if no image is selected
  4820. if (!m_pImageData)
  4821. return E_FAIL;
  4822. // We quietly (the button is disabled but just in case you hit the
  4823. // accelerator key) don't rotate WMF or EMF.
  4824. if (IsEqualGUID(ImageFormatWMF, m_pImageData->_guidFormat) || IsEqualGUID(ImageFormatEMF, m_pImageData->_guidFormat))
  4825. return E_FAIL;
  4826. // Animated GIFs are not editable even though normal GIFs are. This can
  4827. // cause a lot of confusion, so provide some feedback if the user tries
  4828. // to rotate an animated image.
  4829. if (m_pImageData->IsAnimated())
  4830. {
  4831. TCHAR szPath[MAX_PATH];
  4832. PathFromImageData(szPath, ARRAYSIZE(szPath));
  4833. m_fPromptingUser = TRUE;
  4834. ShellMessageBox(_Module.GetModuleInstance(), m_hWnd, MAKEINTRESOURCE(IDS_ROTATE_MESSAGE), MAKEINTRESOURCE(IDS_PROJNAME), MB_OK | MB_ICONERROR, szPath);
  4835. m_fPromptingUser = FALSE;
  4836. return E_FAIL;
  4837. }
  4838. // From here on out you need to goto ErrorCleanup rather than return
  4839. _UpdateButtons(wRotate);
  4840. SetCursorState(SLIDESHOW_CURSOR_BUSY);
  4841. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_ROTATE90CMD, MAKELONG(FALSE, 0));
  4842. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_ROTATE270CMD, MAKELONG(FALSE, 0));
  4843. m_ctlToolbar.UpdateWindow();
  4844. if (m_pTaskScheduler)
  4845. {
  4846. TASKOWNERID toid;
  4847. GetTaskIDFromMode(GTIDFM_DRAW, m_dwMode, &toid);
  4848. m_pTaskScheduler->RemoveTasks(toid, ITSAT_DEFAULT_LPARAM, TRUE);
  4849. }
  4850. HRESULT hr = E_FAIL;
  4851. SIZE sz;
  4852. m_pImageData->GetSize(&sz);
  4853. // if we're thinking we can quietly save
  4854. if (m_pImageData->IsEditable() && !m_fDisableEdit && m_fCanSave)
  4855. {
  4856. // And the rotation might be lossy
  4857. if (::IsEqualGUID(ImageFormatJPEG, m_pImageData->_guidFormat) && ((sz.cx % 16 != 0) || (sz.cy % 16 != 0)))
  4858. {
  4859. int nResult = IDOK;
  4860. if (m_fWarnQuietSave)
  4861. {
  4862. CComBSTR bstrMsg, bstrTitle;
  4863. if (bstrMsg.LoadString(IDS_ROTATE_LOSS) && bstrTitle.LoadString(IDS_PROJNAME))
  4864. {
  4865. // Set default to return IDOK so we know if the user selected something or
  4866. // if the "don't show me this again" bit was respected
  4867. m_fPromptingUser = TRUE;
  4868. nResult = SHMessageBoxCheck(m_hWnd, bstrMsg, bstrTitle, MB_YESNO|MB_ICONWARNING, IDOK, REGSTR_LOSSYROTATE);
  4869. m_fPromptingUser = FALSE;
  4870. }
  4871. if (nResult != IDNO)
  4872. m_fWarnQuietSave = FALSE;
  4873. }
  4874. CRegKey Key;
  4875. if (ERROR_SUCCESS != Key.Open(HKEY_CURRENT_USER, REGSTR_SHIMGVW))
  4876. {
  4877. Key.Create(HKEY_CURRENT_USER, REGSTR_SHIMGVW);
  4878. }
  4879. if (Key.m_hKey != NULL)
  4880. {
  4881. if (nResult == IDOK) // If hidden, then load last result from registry
  4882. {
  4883. DWORD dwResult = 0;
  4884. Key.QueryValue(dwResult, REGSTR_LOSSYROTATE);
  4885. nResult = (int)dwResult;
  4886. }
  4887. else // Otherwise, write this as last result to registry
  4888. {
  4889. DWORD dwResult = (DWORD)nResult;
  4890. Key.SetValue(dwResult, REGSTR_LOSSYROTATE);
  4891. }
  4892. }
  4893. if (nResult == IDNO)
  4894. goto ErrorCleanup;
  4895. }
  4896. }
  4897. CAnnotationSet* pAnnotations = m_ctlPreview.GetAnnotations();
  4898. INT_PTR nCount = pAnnotations->GetCount();
  4899. for (INT_PTR i = 0; i < nCount; i++)
  4900. {
  4901. CAnnotation* pAnnotation = pAnnotations->GetAnnotation(i);
  4902. pAnnotation->Rotate(m_ctlPreview.m_cyImage, m_ctlPreview.m_cxImage, (ID_ROTATE90CMD == wRotate));
  4903. }
  4904. m_ctlPreview.CommitAnnotations();
  4905. hr = m_pImageData->Rotate(dwAngle);
  4906. if (FAILED(hr))
  4907. goto ErrorCleanup;
  4908. // Only if we have an encoder and we haven't been explicitly told not to edit and the source is writeable
  4909. if (m_pImageData->IsEditable() && !m_fDisableEdit && m_fCanSave)
  4910. {
  4911. // on successful edit we immediately save the result. If we want to do multiple edits
  4912. // before saving then you would simply need to wait and call Save later.
  4913. // NB: We currently only allow editing of items loaded from file system paths, no path means
  4914. // no edit. This is stupid, but that's how it is for now.
  4915. hr = ImageDataSave(NULL, FALSE);
  4916. if (SUCCEEDED(hr))
  4917. m_fDirty = FALSE;
  4918. else
  4919. {
  4920. // if we failed to save then go into can't save mode
  4921. if (WINDOW_MODE == m_dwMode)
  4922. m_fCanSave = FALSE;
  4923. }
  4924. }
  4925. _UpdateImage();
  4926. if ((!m_pImageData->IsEditable() || !m_fCanSave) && WINDOW_MODE == m_dwMode)
  4927. {
  4928. if (m_fWarnNoSave)
  4929. {
  4930. m_fWarnNoSave = FALSE;
  4931. CComBSTR bstrMsg, bstrTitle;
  4932. TCHAR szMsg[MAX_PATH];
  4933. if (LoadSPString(IDS_SHIMGVW_ROTATE_CANTSAVE, szMsg, ARRAYSIZE(szMsg)) && bstrTitle.LoadString(IDS_PROJNAME))
  4934. {
  4935. m_fPromptingUser = TRUE;
  4936. SHMessageBoxCheck(m_hWnd, szMsg, bstrTitle, MB_OK|MB_ICONWARNING, IDOK, REGSTR_SAVELESS);
  4937. m_fPromptingUser = FALSE;
  4938. }
  4939. }
  4940. }
  4941. ErrorCleanup:
  4942. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_ROTATE90CMD, MAKELONG(TRUE, 0));
  4943. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_ROTATE270CMD, MAKELONG(TRUE, 0));
  4944. SetCursorState(SLIDESHOW_CURSOR_NOTBUSY);
  4945. return hr;
  4946. }
  4947. STDMETHODIMP CPreviewWnd::NextPage()
  4948. {
  4949. return _PrevNextPage(TRUE);
  4950. }
  4951. STDMETHODIMP CPreviewWnd::PreviousPage()
  4952. {
  4953. return _PrevNextPage(FALSE);
  4954. }
  4955. HRESULT CPreviewWnd::_PrevNextPage(BOOL fForward)
  4956. {
  4957. _RefreshSelection(FALSE);
  4958. if (m_pImageData && m_pImageData->IsMultipage())
  4959. {
  4960. if (m_fDirty)
  4961. {
  4962. m_ctlPreview.CommitAnnotations();
  4963. }
  4964. if (fForward)
  4965. {
  4966. m_pImageData->NextPage();
  4967. }
  4968. else
  4969. {
  4970. m_pImageData->PrevPage();
  4971. }
  4972. _UpdateImage();
  4973. _SetMultipageCommands();
  4974. }
  4975. return S_OK;
  4976. }
  4977. //
  4978. // When the user saves to a format other than TIFF and the current
  4979. // TIFF has annotations, we need to burn annotations
  4980. // into the current image frame before saving.
  4981. // If we ever support other multi-page format encoding besides TIFF, this
  4982. // code will get more complicated
  4983. // assumes the pSID is already locked
  4984. // note that the resulting image is always a color image. Eventually we should make
  4985. // the annotation rendering code respect the bit depth and palette of the
  4986. // current image.
  4987. Image *CPreviewWnd::_BurnAnnotations(IShellImageData *pSID)
  4988. {
  4989. Image *pimg = NULL;
  4990. if (SUCCEEDED(pSID->CloneFrame(&pimg)))
  4991. {
  4992. HDC hdc = ::GetDC(NULL);
  4993. if (hdc)
  4994. {
  4995. LPVOID pBits;
  4996. BITMAPINFO bi = {0};
  4997. bi.bmiHeader.biBitCount = 24;
  4998. bi.bmiHeader.biHeight = pimg->GetHeight();
  4999. bi.bmiHeader.biWidth = pimg->GetWidth();
  5000. bi.bmiHeader.biPlanes = 1;
  5001. bi.bmiHeader.biCompression = BI_RGB;
  5002. bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
  5003. HBITMAP hbm = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, &pBits, NULL, 0);
  5004. if (hbm)
  5005. {
  5006. //
  5007. // For ROP codes to work we need to use pure GDI, then convert the new
  5008. // DIBSection back to an Image object
  5009. //
  5010. HDC hdcMem = ::CreateCompatibleDC(hdc);
  5011. Status s = GenericError;
  5012. if (hdcMem)
  5013. {
  5014. HBITMAP hbmOld = (HBITMAP)::SelectObject(hdcMem, hbm);
  5015. Graphics *g = Graphics::FromHDC(hdcMem);
  5016. if (g)
  5017. {
  5018. s = g->DrawImage(pimg, 0L, 0L, pimg->GetWidth(), pimg->GetHeight());
  5019. g->ReleaseHDC(hdcMem);
  5020. delete g;
  5021. // now draw the annotations
  5022. m_ctlPreview.GetAnnotations()->RenderAllMarks(hdcMem);
  5023. }
  5024. ::SelectObject(hdcMem, hbmOld);
  5025. ::DeleteDC(hdcMem);
  5026. }
  5027. if (Ok == s)
  5028. {
  5029. //
  5030. // Now create a new Bitmap from our DIBSection
  5031. Bitmap *pbmNew = Bitmap::FromHBITMAP(hbm, NULL);
  5032. if (pbmNew)
  5033. {
  5034. pSID->ReplaceFrame(pbmNew);
  5035. }
  5036. }
  5037. DeleteObject(hbm);
  5038. }
  5039. ::ReleaseDC(NULL, hdc);
  5040. }
  5041. }
  5042. return pimg;
  5043. }
  5044. void CPreviewWnd::_InvokePrintWizard()
  5045. {
  5046. if (m_fPrintable)
  5047. {
  5048. HRESULT hr = S_OK;
  5049. if (m_fDirty)
  5050. {
  5051. m_ctlPreview.CommitAnnotations();
  5052. hr = ImageDataSave(NULL, FALSE);
  5053. }
  5054. if (SUCCEEDED(hr))
  5055. {
  5056. m_fDirty = FALSE;
  5057. IPrintPhotosWizardSetInfo *pwiz;
  5058. HRESULT hr = CoCreateInstance(CLSID_PrintPhotosWizard,
  5059. NULL, CLSCTX_INPROC_SERVER,
  5060. IID_PPV_ARG(IPrintPhotosWizardSetInfo, &pwiz));
  5061. if (SUCCEEDED(hr))
  5062. {
  5063. if (m_pImageData != NULL && m_pImageData->_guidFormat == ImageFormatTIFF && m_pImageData->IsMultipage())
  5064. hr = pwiz->SetFileListArray(&(m_ppidls[m_iCurSlide]), 1, 0);
  5065. else
  5066. hr = pwiz->SetFileListArray(m_ppidls, m_cItems, m_iCurSlide);
  5067. if (SUCCEEDED(hr))
  5068. {
  5069. m_fPromptingUser = TRUE;
  5070. hr = pwiz->RunWizard();
  5071. m_fPromptingUser = FALSE;
  5072. }
  5073. pwiz->Release();
  5074. }
  5075. // fall back to the shell if the wizard fails
  5076. if (FAILED(hr))
  5077. {
  5078. _InvokeVerb(TEXT("print"));
  5079. }
  5080. }
  5081. else
  5082. {
  5083. CComBSTR bstrMsg, bstrTitle;
  5084. if (bstrMsg.LoadString(IDS_SAVEFAILED_MSGBOX) && bstrTitle.LoadString(IDS_PROJNAME))
  5085. {
  5086. m_fPromptingUser = TRUE;
  5087. MessageBox(bstrMsg, bstrTitle, MB_OK | MB_ICONERROR | MB_APPLMODAL);
  5088. m_fPromptingUser = FALSE;
  5089. }
  5090. }
  5091. }
  5092. }
  5093. void GetTaskIDFromMode(DWORD dwTask, DWORD dwMode, TASKOWNERID *ptoid)
  5094. {
  5095. switch (dwTask)
  5096. {
  5097. case GTIDFM_DECODE:
  5098. *ptoid = (SLIDESHOW_MODE == dwMode) ? TOID_SlideshowDecode : TOID_PrimaryDecode;
  5099. break;
  5100. case GTIDFM_DRAW:
  5101. *ptoid = (SLIDESHOW_MODE == dwMode) ? TOID_DrawSlideshowFrame : TOID_DrawFrame;
  5102. break;
  5103. default:
  5104. ASSERTMSG(FALSE, "someone passed bad task to GetTaskIDFromMode");
  5105. break;
  5106. }
  5107. }
  5108. // Watch for changes in the file we are currently viewing. This ignores changes
  5109. // in the file being pre-fetched, but we'll live with that for now.
  5110. //
  5111. void CPreviewWnd::_RegisterForChangeNotify(BOOL fRegister)
  5112. {
  5113. // always deregister the current pidl first
  5114. if (m_uRegister)
  5115. {
  5116. SHChangeNotifyDeregister(m_uRegister);
  5117. m_uRegister = 0;
  5118. }
  5119. if (fRegister)
  5120. {
  5121. SHChangeNotifyEntry cne = {0};
  5122. if (SUCCEEDED(_GetItem(m_iCurSlide, (LPITEMIDLIST*)&cne.pidl)))
  5123. {
  5124. m_uRegister = SHChangeNotifyRegister(m_hWnd,
  5125. SHCNRF_ShellLevel | SHCNRF_InterruptLevel | SHCNRF_NewDelivery,
  5126. SHCNE_DISKEVENTS,
  5127. IV_ONCHANGENOTIFY,
  5128. 1, &cne);
  5129. ILFree((LPITEMIDLIST)cne.pidl);
  5130. }
  5131. }
  5132. }
  5133. LRESULT CPreviewWnd::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  5134. {
  5135. // We can assume this notify is for the currently viewed PIDL and the event
  5136. // is one that would force us to reload
  5137. //
  5138. LONG lEvent;
  5139. LPSHChangeNotificationLock pshcnl = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, NULL, &lEvent);
  5140. if (pshcnl)
  5141. {
  5142. // we can't render or manipulate deleted files so don't try
  5143. if (!m_fDirty || lEvent == SHCNE_DELETE || lEvent == SHCNE_RENAMEITEM)
  5144. {
  5145. if (!m_fIgnoreNextNotify)
  5146. {
  5147. m_fDirty = FALSE;
  5148. _PreviewItem(m_iCurSlide);
  5149. }
  5150. else
  5151. {
  5152. m_fIgnoreNextNotify = FALSE;
  5153. }
  5154. bHandled = TRUE;
  5155. }
  5156. SHChangeNotification_Unlock(pshcnl);
  5157. }
  5158. return 0;
  5159. }
  5160. LRESULT CPreviewWnd::OnIsAvailable(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  5161. {
  5162. bHandled = TRUE;
  5163. return !m_fPromptingUser;
  5164. }