Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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