print.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266
  1. /*
  2. * Wordpad implementation - Printing and print preview functions
  3. *
  4. * Copyright 2007-2008 by Alexander N. Sørnes <alex@thehandofagony.com>
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #include <windows.h>
  21. #include <richedit.h>
  22. #include <commctrl.h>
  23. #include <commdlg.h>
  24. #include "wordpad.h"
  25. typedef struct _previewinfo
  26. {
  27. int page;
  28. int pages_shown;
  29. int saved_pages_shown;
  30. int *pageEnds, pageCapacity;
  31. int textlength;
  32. HDC hdc;
  33. HDC hdc2;
  34. RECT window;
  35. RECT rcPage;
  36. SIZE bmSize;
  37. SIZE bmScaledSize;
  38. SIZE spacing;
  39. float zoomratio;
  40. int zoomlevel;
  41. LPWSTR wszFileName;
  42. } previewinfo, *ppreviewinfo;
  43. static HGLOBAL devMode;
  44. static HGLOBAL devNames;
  45. static RECT margins;
  46. static previewinfo preview;
  47. extern const WCHAR wszPreviewWndClass[];
  48. static const WCHAR var_pagemargin[] = {'P','a','g','e','M','a','r','g','i','n',0};
  49. static const WCHAR var_previewpages[] = {'P','r','e','v','i','e','w','P','a','g','e','s',0};
  50. static LPWSTR get_print_file_filter(HWND hMainWnd)
  51. {
  52. static WCHAR wszPrintFilter[MAX_STRING_LEN*2+6+4+1];
  53. const WCHAR files_prn[] = {'*','.','P','R','N',0};
  54. const WCHAR files_all[] = {'*','.','*','\0'};
  55. LPWSTR p;
  56. HINSTANCE hInstance = GetModuleHandleW(0);
  57. p = wszPrintFilter;
  58. LoadStringW(hInstance, STRING_PRINTER_FILES_PRN, p, MAX_STRING_LEN);
  59. p += lstrlenW(p) + 1;
  60. lstrcpyW(p, files_prn);
  61. p += lstrlenW(p) + 1;
  62. LoadStringW(hInstance, STRING_ALL_FILES, p, MAX_STRING_LEN);
  63. p += lstrlenW(p) + 1;
  64. lstrcpyW(p, files_all);
  65. p += lstrlenW(p) + 1;
  66. *p = 0;
  67. return wszPrintFilter;
  68. }
  69. void registry_set_pagemargins(HKEY hKey)
  70. {
  71. RegSetValueExW(hKey, var_pagemargin, 0, REG_BINARY, (LPBYTE)&margins, sizeof(RECT));
  72. }
  73. void registry_read_pagemargins(HKEY hKey)
  74. {
  75. DWORD size = sizeof(RECT);
  76. if(!hKey || RegQueryValueExW(hKey, var_pagemargin, 0, NULL, (LPBYTE)&margins,
  77. &size) != ERROR_SUCCESS || size != sizeof(RECT))
  78. SetRect(&margins, 1757, 1417, 1757, 1417);
  79. }
  80. void registry_set_previewpages(HKEY hKey)
  81. {
  82. RegSetValueExW(hKey, var_previewpages, 0, REG_DWORD,
  83. (LPBYTE)&preview.pages_shown, sizeof(DWORD));
  84. }
  85. void registry_read_previewpages(HKEY hKey)
  86. {
  87. DWORD size = sizeof(DWORD);
  88. if(!hKey ||
  89. RegQueryValueExW(hKey, var_previewpages, 0, NULL,
  90. (LPBYTE)&preview.pages_shown, &size) != ERROR_SUCCESS ||
  91. size != sizeof(DWORD))
  92. {
  93. preview.pages_shown = 1;
  94. } else {
  95. if (preview.pages_shown < 1) preview.pages_shown = 1;
  96. else if (preview.pages_shown > 2) preview.pages_shown = 2;
  97. }
  98. }
  99. static void AddTextButton(HWND hRebarWnd, UINT string, UINT command, UINT id)
  100. {
  101. REBARBANDINFOW rb;
  102. HINSTANCE hInstance = GetModuleHandleW(0);
  103. WCHAR text[MAX_STRING_LEN];
  104. HWND hButton;
  105. LoadStringW(hInstance, string, text, MAX_STRING_LEN);
  106. hButton = CreateWindowW(WC_BUTTONW, text,
  107. WS_VISIBLE | WS_CHILD, 5, 5, 100, 15,
  108. hRebarWnd, ULongToHandle(command), hInstance, NULL);
  109. rb.cbSize = REBARBANDINFOW_V6_SIZE;
  110. rb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_ID;
  111. rb.fStyle = RBBS_NOGRIPPER | RBBS_VARIABLEHEIGHT;
  112. rb.hwndChild = hButton;
  113. rb.cyChild = rb.cyMinChild = 22;
  114. rb.cx = rb.cxMinChild = 90;
  115. rb.cxIdeal = 100;
  116. rb.wID = id;
  117. SendMessageW(hRebarWnd, RB_INSERTBANDW, -1, (LPARAM)&rb);
  118. }
  119. static HDC make_dc(void)
  120. {
  121. if(devNames && devMode)
  122. {
  123. LPDEVNAMES dn = GlobalLock(devNames);
  124. LPDEVMODEW dm = GlobalLock(devMode);
  125. HDC ret;
  126. ret = CreateDCW((LPWSTR)dn + dn->wDriverOffset,
  127. (LPWSTR)dn + dn->wDeviceOffset, 0, dm);
  128. GlobalUnlock(dn);
  129. GlobalUnlock(dm);
  130. return ret;
  131. } else
  132. {
  133. return 0;
  134. }
  135. }
  136. static LONG twips_to_centmm(int twips)
  137. {
  138. return MulDiv(twips, CENTMM_PER_INCH, TWIPS_PER_INCH);
  139. }
  140. static LONG centmm_to_twips(int mm)
  141. {
  142. return MulDiv(mm, TWIPS_PER_INCH, CENTMM_PER_INCH);
  143. }
  144. static LONG twips_to_pixels(int twips, int dpi)
  145. {
  146. return MulDiv(twips, dpi, TWIPS_PER_INCH);
  147. }
  148. static LONG devunits_to_twips(int units, int dpi)
  149. {
  150. return MulDiv(units, TWIPS_PER_INCH, dpi);
  151. }
  152. static RECT get_print_rect(HDC hdc)
  153. {
  154. RECT rc;
  155. int width, height;
  156. if(hdc)
  157. {
  158. int dpiY = GetDeviceCaps(hdc, LOGPIXELSY);
  159. int dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
  160. width = devunits_to_twips(GetDeviceCaps(hdc, PHYSICALWIDTH), dpiX);
  161. height = devunits_to_twips(GetDeviceCaps(hdc, PHYSICALHEIGHT), dpiY);
  162. } else
  163. {
  164. width = centmm_to_twips(18500);
  165. height = centmm_to_twips(27000);
  166. }
  167. SetRect(&rc, margins.left, margins.top, width - margins.right, height - margins.bottom);
  168. return rc;
  169. }
  170. void target_device(HWND hMainWnd, DWORD wordWrap)
  171. {
  172. HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
  173. if(wordWrap == ID_WORDWRAP_MARGIN)
  174. {
  175. int width = 0;
  176. LRESULT result;
  177. HDC hdc = make_dc();
  178. RECT rc = get_print_rect(hdc);
  179. width = rc.right - rc.left;
  180. if(!hdc)
  181. {
  182. HDC hMaindc = GetDC(hMainWnd);
  183. hdc = CreateCompatibleDC(hMaindc);
  184. ReleaseDC(hMainWnd, hMaindc);
  185. }
  186. result = SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, (WPARAM)hdc, width);
  187. DeleteDC(hdc);
  188. if (result)
  189. return;
  190. /* otherwise EM_SETTARGETDEVICE failed, so fall back on wrapping
  191. * to window using the NULL DC. */
  192. }
  193. if (wordWrap != ID_WORDWRAP_NONE) {
  194. SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, 0, 0);
  195. } else {
  196. SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, 0, 1);
  197. }
  198. }
  199. static LPWSTR dialog_print_to_file(HWND hMainWnd)
  200. {
  201. OPENFILENAMEW ofn;
  202. static WCHAR file[MAX_PATH] = {'O','U','T','P','U','T','.','P','R','N',0};
  203. static const WCHAR defExt[] = {'P','R','N',0};
  204. static LPWSTR file_filter;
  205. if(!file_filter)
  206. file_filter = get_print_file_filter(hMainWnd);
  207. ZeroMemory(&ofn, sizeof(ofn));
  208. ofn.lStructSize = sizeof(ofn);
  209. ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
  210. ofn.hwndOwner = hMainWnd;
  211. ofn.lpstrFilter = file_filter;
  212. ofn.lpstrFile = file;
  213. ofn.nMaxFile = MAX_PATH;
  214. ofn.lpstrDefExt = defExt;
  215. if(GetSaveFileNameW(&ofn))
  216. return file;
  217. else
  218. return FALSE;
  219. }
  220. static void char_from_pagenum(HWND hEditorWnd, FORMATRANGE *fr, int page)
  221. {
  222. int i;
  223. fr->chrg.cpMin = 0;
  224. for(i = 1; i < page; i++)
  225. {
  226. int bottom = fr->rc.bottom;
  227. fr->chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, (LPARAM)fr);
  228. fr->rc.bottom = bottom;
  229. }
  230. }
  231. static HWND get_ruler_wnd(HWND hMainWnd)
  232. {
  233. return GetDlgItem(GetDlgItem(hMainWnd, IDC_REBAR), IDC_RULER);
  234. }
  235. void redraw_ruler(HWND hRulerWnd)
  236. {
  237. RECT rc;
  238. GetClientRect(hRulerWnd, &rc);
  239. InvalidateRect(hRulerWnd, &rc, TRUE);
  240. }
  241. static void update_ruler(HWND hRulerWnd)
  242. {
  243. SendMessageW(hRulerWnd, WM_USER, 0, 0);
  244. redraw_ruler(hRulerWnd);
  245. }
  246. static void add_ruler_units(HDC hdcRuler, RECT* drawRect, BOOL NewMetrics, LONG EditLeftmost)
  247. {
  248. static HDC hdc;
  249. if(NewMetrics)
  250. {
  251. static HBITMAP hBitmap;
  252. int i, x, y, RulerTextEnd;
  253. int CmPixels;
  254. int QuarterCmPixels;
  255. HFONT hFont;
  256. WCHAR FontName[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0};
  257. if(hdc)
  258. {
  259. DeleteDC(hdc);
  260. DeleteObject(hBitmap);
  261. }
  262. hdc = CreateCompatibleDC(0);
  263. CmPixels = twips_to_pixels(centmm_to_twips(1000), GetDeviceCaps(hdc, LOGPIXELSX));
  264. QuarterCmPixels = (int)((float)CmPixels / 4.0);
  265. hBitmap = CreateCompatibleBitmap(hdc, drawRect->right, drawRect->bottom);
  266. SelectObject(hdc, hBitmap);
  267. FillRect(hdc, drawRect, GetStockObject(WHITE_BRUSH));
  268. hFont = CreateFontW(10, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FontName);
  269. SelectObject(hdc, hFont);
  270. SetBkMode(hdc, TRANSPARENT);
  271. SetTextAlign(hdc, TA_CENTER);
  272. y = (int)(((float)drawRect->bottom - (float)drawRect->top) / 2.0) + 1;
  273. RulerTextEnd = drawRect->right - EditLeftmost + 1;
  274. for(i = 1, x = EditLeftmost; x < (drawRect->right - EditLeftmost + 1); i ++)
  275. {
  276. WCHAR str[3];
  277. WCHAR format[] = {'%','d',0};
  278. int x2 = x;
  279. x2 += QuarterCmPixels;
  280. if(x2 > RulerTextEnd)
  281. break;
  282. MoveToEx(hdc, x2, y, NULL);
  283. LineTo(hdc, x2, y+2);
  284. x2 += QuarterCmPixels;
  285. if(x2 > RulerTextEnd)
  286. break;
  287. MoveToEx(hdc, x2, y - 3, NULL);
  288. LineTo(hdc, x2, y + 3);
  289. x2 += QuarterCmPixels;
  290. if(x2 > RulerTextEnd)
  291. break;
  292. MoveToEx(hdc, x2, y, NULL);
  293. LineTo(hdc, x2, y+2);
  294. x += CmPixels;
  295. if(x > RulerTextEnd)
  296. break;
  297. wsprintfW(str, format, i);
  298. TextOutW(hdc, x, 5, str, lstrlenW(str));
  299. }
  300. DeleteObject(hFont);
  301. }
  302. BitBlt(hdcRuler, 0, 0, drawRect->right, drawRect->bottom, hdc, 0, 0, SRCAND);
  303. }
  304. static void paint_ruler(HWND hWnd, LONG EditLeftmost, BOOL NewMetrics)
  305. {
  306. PAINTSTRUCT ps;
  307. HDC hdc = BeginPaint(hWnd, &ps);
  308. HDC hdcPrint = make_dc();
  309. RECT printRect = get_print_rect(hdcPrint);
  310. RECT drawRect;
  311. GetClientRect(hWnd, &drawRect);
  312. FillRect(hdc, &drawRect, GetSysColorBrush(COLOR_MENU));
  313. InflateRect(&drawRect, 0, -3);
  314. drawRect.left = EditLeftmost;
  315. drawRect.right = twips_to_pixels(printRect.right - margins.left, GetDeviceCaps(hdc, LOGPIXELSX));
  316. FillRect(hdc, &drawRect, GetStockObject(WHITE_BRUSH));
  317. drawRect.top--;
  318. drawRect.bottom++;
  319. DrawEdge(hdc, &drawRect, EDGE_SUNKEN, BF_RECT);
  320. drawRect.left = drawRect.right - 1;
  321. drawRect.right = twips_to_pixels(printRect.right + margins.right - margins.left, GetDeviceCaps(hdc, LOGPIXELSX));
  322. DrawEdge(hdc, &drawRect, EDGE_ETCHED, BF_RECT);
  323. drawRect.left = 0;
  324. drawRect.top = 0;
  325. add_ruler_units(hdc, &drawRect, NewMetrics, EditLeftmost);
  326. SelectObject(hdc, GetStockObject(BLACK_BRUSH));
  327. DeleteDC(hdcPrint);
  328. EndPaint(hWnd, &ps);
  329. }
  330. LRESULT CALLBACK ruler_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  331. {
  332. static WNDPROC pPrevRulerProc;
  333. static LONG EditLeftmost;
  334. static BOOL NewMetrics;
  335. switch(msg)
  336. {
  337. case WM_USER:
  338. if(wParam)
  339. {
  340. EditLeftmost = ((POINTL*)wParam)->x;
  341. pPrevRulerProc = (WNDPROC)lParam;
  342. }
  343. NewMetrics = TRUE;
  344. break;
  345. case WM_PAINT:
  346. paint_ruler(hWnd, EditLeftmost, NewMetrics);
  347. break;
  348. default:
  349. return CallWindowProcW(pPrevRulerProc, hWnd, msg, wParam, lParam);
  350. }
  351. return 0;
  352. }
  353. static void print(LPPRINTDLGW pd, LPWSTR wszFileName)
  354. {
  355. FORMATRANGE fr;
  356. DOCINFOW di;
  357. HWND hEditorWnd = GetDlgItem(pd->hwndOwner, IDC_EDITOR);
  358. int printedPages = 0;
  359. fr.hdc = pd->hDC;
  360. fr.hdcTarget = pd->hDC;
  361. fr.rc = get_print_rect(fr.hdc);
  362. SetRect(&fr.rcPage, 0, 0, fr.rc.right + margins.right, fr.rc.bottom + margins.bottom);
  363. ZeroMemory(&di, sizeof(di));
  364. di.cbSize = sizeof(di);
  365. di.lpszDocName = wszFileName;
  366. if(pd->Flags & PD_PRINTTOFILE)
  367. {
  368. di.lpszOutput = dialog_print_to_file(pd->hwndOwner);
  369. if(!di.lpszOutput)
  370. return;
  371. }
  372. if(pd->Flags & PD_SELECTION)
  373. {
  374. SendMessageW(hEditorWnd, EM_EXGETSEL, 0, (LPARAM)&fr.chrg);
  375. } else
  376. {
  377. GETTEXTLENGTHEX gt;
  378. gt.flags = GTL_DEFAULT;
  379. gt.codepage = 1200;
  380. fr.chrg.cpMin = 0;
  381. fr.chrg.cpMax = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0);
  382. if(pd->Flags & PD_PAGENUMS)
  383. char_from_pagenum(hEditorWnd, &fr, pd->nToPage);
  384. }
  385. StartDocW(fr.hdc, &di);
  386. do
  387. {
  388. if(StartPage(fr.hdc) <= 0)
  389. break;
  390. fr.chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)&fr);
  391. if(EndPage(fr.hdc) <= 0)
  392. break;
  393. printedPages++;
  394. if((pd->Flags & PD_PAGENUMS) && (printedPages > (pd->nToPage - pd->nFromPage)))
  395. break;
  396. }
  397. while(fr.chrg.cpMin && fr.chrg.cpMin < fr.chrg.cpMax);
  398. EndDoc(fr.hdc);
  399. SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, 0);
  400. }
  401. void dialog_printsetup(HWND hMainWnd)
  402. {
  403. PAGESETUPDLGW ps;
  404. ZeroMemory(&ps, sizeof(ps));
  405. ps.lStructSize = sizeof(ps);
  406. ps.hwndOwner = hMainWnd;
  407. ps.Flags = PSD_INHUNDREDTHSOFMILLIMETERS | PSD_MARGINS;
  408. SetRect(&ps.rtMargin, twips_to_centmm(margins.left), twips_to_centmm(margins.top),
  409. twips_to_centmm(margins.right), twips_to_centmm(margins.bottom));
  410. ps.hDevMode = devMode;
  411. ps.hDevNames = devNames;
  412. if(PageSetupDlgW(&ps))
  413. {
  414. SetRect(&margins, centmm_to_twips(ps.rtMargin.left), centmm_to_twips(ps.rtMargin.top),
  415. centmm_to_twips(ps.rtMargin.right), centmm_to_twips(ps.rtMargin.bottom));
  416. devMode = ps.hDevMode;
  417. devNames = ps.hDevNames;
  418. update_ruler(get_ruler_wnd(hMainWnd));
  419. }
  420. }
  421. void get_default_printer_opts(void)
  422. {
  423. PRINTDLGW pd;
  424. ZeroMemory(&pd, sizeof(pd));
  425. ZeroMemory(&pd, sizeof(pd));
  426. pd.lStructSize = sizeof(pd);
  427. pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT;
  428. pd.hDevMode = devMode;
  429. PrintDlgW(&pd);
  430. devMode = pd.hDevMode;
  431. devNames = pd.hDevNames;
  432. }
  433. void print_quick(HWND hMainWnd, LPWSTR wszFileName)
  434. {
  435. PRINTDLGW pd;
  436. ZeroMemory(&pd, sizeof(pd));
  437. pd.hwndOwner = hMainWnd;
  438. pd.hDC = make_dc();
  439. print(&pd, wszFileName);
  440. DeleteDC(pd.hDC);
  441. }
  442. void dialog_print(HWND hMainWnd, LPWSTR wszFileName)
  443. {
  444. PRINTDLGW pd;
  445. HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
  446. int from = 0;
  447. int to = 0;
  448. ZeroMemory(&pd, sizeof(pd));
  449. pd.lStructSize = sizeof(pd);
  450. pd.hwndOwner = hMainWnd;
  451. pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE;
  452. pd.nMinPage = 1;
  453. pd.nMaxPage = -1;
  454. pd.hDevMode = devMode;
  455. pd.hDevNames = devNames;
  456. SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&from, (LPARAM)&to);
  457. if(from == to)
  458. pd.Flags |= PD_NOSELECTION;
  459. if(PrintDlgW(&pd))
  460. {
  461. devMode = pd.hDevMode;
  462. devNames = pd.hDevNames;
  463. print(&pd, wszFileName);
  464. update_ruler(get_ruler_wnd(hMainWnd));
  465. }
  466. }
  467. static void preview_bar_show(HWND hMainWnd, BOOL show)
  468. {
  469. HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
  470. int i;
  471. if(show)
  472. {
  473. REBARBANDINFOW rb;
  474. HWND hStatic;
  475. UINT num_pages_string = preview.pages_shown > 1 ? STRING_PREVIEW_ONEPAGE :
  476. STRING_PREVIEW_TWOPAGES;
  477. AddTextButton(hReBar, STRING_PREVIEW_PRINT, ID_PRINT, BANDID_PREVIEW_BTN1);
  478. AddTextButton(hReBar, STRING_PREVIEW_NEXTPAGE, ID_PREVIEW_NEXTPAGE, BANDID_PREVIEW_BTN2);
  479. AddTextButton(hReBar, STRING_PREVIEW_PREVPAGE, ID_PREVIEW_PREVPAGE, BANDID_PREVIEW_BTN3);
  480. AddTextButton(hReBar, num_pages_string, ID_PREVIEW_NUMPAGES, BANDID_PREVIEW_BTN4);
  481. AddTextButton(hReBar, STRING_PREVIEW_ZOOMIN, ID_PREVIEW_ZOOMIN, BANDID_PREVIEW_BTN5);
  482. AddTextButton(hReBar, STRING_PREVIEW_ZOOMOUT, ID_PREVIEW_ZOOMOUT, BANDID_PREVIEW_BTN6);
  483. AddTextButton(hReBar, STRING_PREVIEW_CLOSE, ID_FILE_EXIT, BANDID_PREVIEW_BTN7);
  484. hStatic = CreateWindowW(WC_STATICW, NULL,
  485. WS_VISIBLE | WS_CHILD, 0, 0, 0, 0,
  486. hReBar, NULL, NULL, NULL);
  487. rb.cbSize = REBARBANDINFOW_V6_SIZE;
  488. rb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_ID;
  489. rb.fStyle = RBBS_NOGRIPPER | RBBS_VARIABLEHEIGHT;
  490. rb.hwndChild = hStatic;
  491. rb.cyChild = rb.cyMinChild = 22;
  492. rb.cx = rb.cxMinChild = 90;
  493. rb.cxIdeal = 100;
  494. rb.wID = BANDID_PREVIEW_BUFFER;
  495. SendMessageW(hReBar, RB_INSERTBANDW, -1, (LPARAM)&rb);
  496. } else
  497. {
  498. for(i = 0; i <= PREVIEW_BUTTONS; i++)
  499. SendMessageW(hReBar, RB_DELETEBAND, SendMessageW(hReBar, RB_IDTOINDEX, BANDID_PREVIEW_BTN1+i, 0), 0);
  500. }
  501. }
  502. static const int min_spacing = 10;
  503. static void update_preview_scrollbars(HWND hwndPreview, RECT *window)
  504. {
  505. SCROLLINFO sbi;
  506. sbi.cbSize = sizeof(sbi);
  507. sbi.fMask = SIF_PAGE|SIF_RANGE;
  508. sbi.nMin = 0;
  509. if (preview.zoomlevel == 0)
  510. {
  511. /* Hide scrollbars when zoomed out. */
  512. sbi.nMax = 0;
  513. sbi.nPage = window->right;
  514. SetScrollInfo(hwndPreview, SB_HORZ, &sbi, TRUE);
  515. sbi.nPage = window->bottom;
  516. SetScrollInfo(hwndPreview, SB_VERT, &sbi, TRUE);
  517. } else {
  518. sbi.nMax = preview.bmScaledSize.cx * preview.pages_shown +
  519. min_spacing * (preview.pages_shown + 1);
  520. sbi.nPage = window->right;
  521. SetScrollInfo(hwndPreview, SB_HORZ, &sbi, TRUE);
  522. /* Change in the horizontal scrollbar visibility affects the
  523. * client rect, so update the client rect. */
  524. GetClientRect(hwndPreview, window);
  525. sbi.nMax = preview.bmScaledSize.cy + min_spacing * 2;
  526. sbi.nPage = window->bottom;
  527. SetScrollInfo(hwndPreview, SB_VERT, &sbi, TRUE);
  528. }
  529. }
  530. static void update_preview_sizes(HWND hwndPreview, BOOL zoomLevelUpdated)
  531. {
  532. RECT window;
  533. GetClientRect(hwndPreview, &window);
  534. /* The zoom ratio isn't updated for partial zoom because of resizing the window. */
  535. if (zoomLevelUpdated || preview.zoomlevel != 1)
  536. {
  537. float ratio, ratioHeight, ratioWidth;
  538. if (preview.zoomlevel == 2)
  539. {
  540. ratio = 1.0;
  541. } else {
  542. ratioHeight = (window.bottom - min_spacing * 2) / (float)preview.bmSize.cy;
  543. ratioWidth = (float)(window.right -
  544. min_spacing * (preview.pages_shown + 1)) /
  545. (preview.pages_shown * preview.bmSize.cx);
  546. if(ratioWidth > ratioHeight)
  547. ratio = ratioHeight;
  548. else
  549. ratio = ratioWidth;
  550. if (preview.zoomlevel == 1)
  551. ratio += (1.0 - ratio) / 2;
  552. }
  553. preview.zoomratio = ratio;
  554. }
  555. preview.bmScaledSize.cx = preview.bmSize.cx * preview.zoomratio;
  556. preview.bmScaledSize.cy = preview.bmSize.cy * preview.zoomratio;
  557. preview.spacing.cy = max(min_spacing, (window.bottom - preview.bmScaledSize.cy) / 2);
  558. preview.spacing.cx = (window.right -
  559. preview.bmScaledSize.cx * preview.pages_shown) /
  560. (preview.pages_shown + 1);
  561. if (preview.spacing.cx < min_spacing)
  562. preview.spacing.cx = min_spacing;
  563. update_preview_scrollbars(hwndPreview, &window);
  564. }
  565. static void draw_margin_lines(HDC hdc, int x, int y, float ratio)
  566. {
  567. HPEN hPen, oldPen;
  568. SIZE dpi;
  569. RECT page_margin = preview.rcPage;
  570. dpi.cx = GetDeviceCaps(hdc, LOGPIXELSX);
  571. dpi.cy = GetDeviceCaps(hdc, LOGPIXELSY);
  572. SetRect(&page_margin, preview.rcPage.left + margins.left, preview.rcPage.top + margins.top,
  573. preview.rcPage.right - margins.right, preview.rcPage.bottom - margins.bottom);
  574. page_margin.left = (int)((float)twips_to_pixels(page_margin.left, dpi.cx) * ratio);
  575. page_margin.top = (int)((float)twips_to_pixels(page_margin.top, dpi.cy) * ratio);
  576. page_margin.bottom = (int)((float)twips_to_pixels(page_margin.bottom, dpi.cy) * ratio);
  577. page_margin.right = (int)((float)twips_to_pixels(page_margin.right, dpi.cx) * ratio);
  578. OffsetRect(&page_margin, x, y);
  579. hPen = CreatePen(PS_DOT, 1, RGB(0,0,0));
  580. oldPen = SelectObject(hdc, hPen);
  581. MoveToEx(hdc, x, page_margin.top, NULL);
  582. LineTo(hdc, x + preview.bmScaledSize.cx, page_margin.top);
  583. MoveToEx(hdc, x, page_margin.bottom, NULL);
  584. LineTo(hdc, x + preview.bmScaledSize.cx, page_margin.bottom);
  585. MoveToEx(hdc, page_margin.left, y, NULL);
  586. LineTo(hdc, page_margin.left, y + preview.bmScaledSize.cy);
  587. MoveToEx(hdc, page_margin.right, y, NULL);
  588. LineTo(hdc, page_margin.right, y + preview.bmScaledSize.cy);
  589. SelectObject(hdc, oldPen);
  590. DeleteObject(hPen);
  591. }
  592. static BOOL is_last_preview_page(int page)
  593. {
  594. return preview.pageEnds[page - 1] >= preview.textlength;
  595. }
  596. void init_preview(HWND hMainWnd, LPWSTR wszFileName)
  597. {
  598. HINSTANCE hInstance = GetModuleHandleW(0);
  599. preview.page = 1;
  600. preview.hdc = 0;
  601. preview.hdc2 = 0;
  602. preview.wszFileName = wszFileName;
  603. preview.zoomratio = 0;
  604. preview.zoomlevel = 0;
  605. preview_bar_show(hMainWnd, TRUE);
  606. CreateWindowExW(0, wszPreviewWndClass, NULL,
  607. WS_VISIBLE | WS_CHILD | WS_VSCROLL | WS_HSCROLL,
  608. 0, 0, 200, 10, hMainWnd, (HMENU)IDC_PREVIEW, hInstance, NULL);
  609. }
  610. void close_preview(HWND hMainWnd)
  611. {
  612. HWND hwndPreview = GetDlgItem(hMainWnd, IDC_PREVIEW);
  613. preview.window.right = 0;
  614. preview.window.bottom = 0;
  615. preview.page = 0;
  616. HeapFree(GetProcessHeap(), 0, preview.pageEnds);
  617. preview.pageEnds = NULL;
  618. preview.pageCapacity = 0;
  619. if (preview.zoomlevel > 0)
  620. preview.pages_shown = preview.saved_pages_shown;
  621. if(preview.hdc) {
  622. HBITMAP oldbm = GetCurrentObject(preview.hdc, OBJ_BITMAP);
  623. DeleteDC(preview.hdc);
  624. DeleteObject(oldbm);
  625. preview.hdc = NULL;
  626. }
  627. if(preview.hdc2) {
  628. HBITMAP oldbm = GetCurrentObject(preview.hdc2, OBJ_BITMAP);
  629. DeleteDC(preview.hdc2);
  630. DeleteObject(oldbm);
  631. preview.hdc2 = NULL;
  632. }
  633. preview_bar_show(hMainWnd, FALSE);
  634. DestroyWindow(hwndPreview);
  635. }
  636. BOOL preview_isactive(void)
  637. {
  638. return preview.page != 0;
  639. }
  640. static void draw_preview(HWND hEditorWnd, FORMATRANGE* lpFr, RECT* paper, int page)
  641. {
  642. int bottom;
  643. if (!preview.pageEnds)
  644. {
  645. preview.pageCapacity = 32;
  646. preview.pageEnds = HeapAlloc(GetProcessHeap(), 0,
  647. sizeof(int) * preview.pageCapacity);
  648. if (!preview.pageEnds) return;
  649. } else if (page >= preview.pageCapacity) {
  650. int *new_buffer;
  651. new_buffer = HeapReAlloc(GetProcessHeap(), 0, preview.pageEnds,
  652. sizeof(int) * preview.pageCapacity * 2);
  653. if (!new_buffer) return;
  654. preview.pageCapacity *= 2;
  655. preview.pageEnds = new_buffer;
  656. }
  657. FillRect(lpFr->hdc, paper, GetStockObject(WHITE_BRUSH));
  658. if (page > 1 && is_last_preview_page(page - 1)) return;
  659. lpFr->chrg.cpMin = page <= 1 ? 0 : preview.pageEnds[page-2];
  660. bottom = lpFr->rc.bottom;
  661. preview.pageEnds[page-1] = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)lpFr);
  662. /* EM_FORMATRANGE sets fr.rc.bottom to indicate the area printed in,
  663. * but we want to keep the original for drawing margins */
  664. lpFr->rc.bottom = bottom;
  665. SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, 0);
  666. }
  667. static void update_preview_buttons(HWND hMainWnd)
  668. {
  669. HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
  670. EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_PREVPAGE), preview.page > 1);
  671. EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_NEXTPAGE),
  672. !is_last_preview_page(preview.page) &&
  673. !is_last_preview_page(preview.page + preview.pages_shown - 1));
  674. EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_NUMPAGES),
  675. preview.pages_shown > 1 ||
  676. (!is_last_preview_page(1) && preview.zoomlevel == 0));
  677. EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_ZOOMIN), preview.zoomlevel < 2);
  678. EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_ZOOMOUT), preview.zoomlevel > 0);
  679. }
  680. static LRESULT print_preview(HWND hwndPreview)
  681. {
  682. HPEN hPen, oldPen;
  683. HDC hdc;
  684. HRGN back_rgn, excl_rgn;
  685. RECT window, background;
  686. PAINTSTRUCT ps;
  687. int x, y;
  688. hdc = BeginPaint(hwndPreview, &ps);
  689. GetClientRect(hwndPreview, &window);
  690. back_rgn = CreateRectRgnIndirect(&window);
  691. x = preview.spacing.cx - GetScrollPos(hwndPreview, SB_HORZ);
  692. y = preview.spacing.cy - GetScrollPos(hwndPreview, SB_VERT);
  693. /* draw page outlines */
  694. hPen = CreatePen(PS_SOLID|PS_INSIDEFRAME, 2, RGB(0,0,0));
  695. oldPen = SelectObject(hdc, hPen);
  696. SetRect(&background, x - 2, y - 2, x + preview.bmScaledSize.cx + 2,
  697. y + preview.bmScaledSize.cy + 2);
  698. Rectangle(hdc, background.left, background.top,
  699. background.right, background.bottom);
  700. excl_rgn = CreateRectRgnIndirect(&background);
  701. CombineRgn(back_rgn, back_rgn, excl_rgn, RGN_DIFF);
  702. if(preview.pages_shown > 1)
  703. {
  704. background.left += preview.bmScaledSize.cx + preview.spacing.cx;
  705. background.right += preview.bmScaledSize.cx + preview.spacing.cx;
  706. Rectangle(hdc, background.left, background.top,
  707. background.right, background.bottom);
  708. SetRectRgn(excl_rgn, background.left, background.top,
  709. background.right, background.bottom);
  710. CombineRgn(back_rgn, back_rgn, excl_rgn, RGN_DIFF);
  711. }
  712. SelectObject(hdc, oldPen);
  713. DeleteObject(hPen);
  714. FillRgn(hdc, back_rgn, GetStockObject(GRAY_BRUSH));
  715. DeleteObject(excl_rgn);
  716. DeleteObject(back_rgn);
  717. StretchBlt(hdc, x, y, preview.bmScaledSize.cx, preview.bmScaledSize.cy,
  718. preview.hdc, 0, 0, preview.bmSize.cx, preview.bmSize.cy, SRCCOPY);
  719. draw_margin_lines(hdc, x, y, preview.zoomratio);
  720. if(preview.pages_shown > 1)
  721. {
  722. if (!is_last_preview_page(preview.page)) {
  723. x += preview.spacing.cx + preview.bmScaledSize.cx;
  724. StretchBlt(hdc, x, y,
  725. preview.bmScaledSize.cx, preview.bmScaledSize.cy,
  726. preview.hdc2, 0, 0,
  727. preview.bmSize.cx, preview.bmSize.cy, SRCCOPY);
  728. draw_margin_lines(hdc, x, y, preview.zoomratio);
  729. } else {
  730. InflateRect(&background, -2, -2);
  731. FillRect(hdc, &background, GetStockObject(WHITE_BRUSH));
  732. }
  733. }
  734. preview.window = window;
  735. EndPaint(hwndPreview, &ps);
  736. return 0;
  737. }
  738. static void update_preview_statusbar(HWND hMainWnd)
  739. {
  740. HWND hStatusbar = GetDlgItem(hMainWnd, IDC_STATUSBAR);
  741. HINSTANCE hInst = GetModuleHandleW(0);
  742. WCHAR *p;
  743. WCHAR wstr[MAX_STRING_LEN];
  744. p = wstr;
  745. if (preview.pages_shown < 2 || is_last_preview_page(preview.page))
  746. {
  747. static const WCHAR fmt[] = {' ','%','d','\0'};
  748. p += LoadStringW(hInst, STRING_PREVIEW_PAGE, wstr, MAX_STRING_LEN);
  749. wsprintfW(p, fmt, preview.page);
  750. } else {
  751. static const WCHAR fmt[] = {' ','%','d','-','%','d','\0'};
  752. p += LoadStringW(hInst, STRING_PREVIEW_PAGES, wstr, MAX_STRING_LEN);
  753. wsprintfW(p, fmt, preview.page, preview.page + 1);
  754. }
  755. SetWindowTextW(hStatusbar, wstr);
  756. }
  757. /* Update for page changes. */
  758. static void update_preview(HWND hMainWnd)
  759. {
  760. RECT paper;
  761. HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
  762. HWND hwndPreview = GetDlgItem(hMainWnd, IDC_PREVIEW);
  763. HBITMAP hBitmapCapture;
  764. FORMATRANGE fr;
  765. HDC hdc = GetDC(hwndPreview);
  766. fr.hdcTarget = make_dc();
  767. fr.rc = fr.rcPage = preview.rcPage;
  768. fr.rc.left += margins.left;
  769. fr.rc.top += margins.top;
  770. fr.rc.bottom -= margins.bottom;
  771. fr.rc.right -= margins.right;
  772. fr.chrg.cpMin = 0;
  773. fr.chrg.cpMax = preview.textlength;
  774. SetRect(&paper, 0, 0, preview.bmSize.cx, preview.bmSize.cy);
  775. if (!preview.hdc) {
  776. preview.hdc = CreateCompatibleDC(hdc);
  777. hBitmapCapture = CreateCompatibleBitmap(hdc, preview.bmSize.cx, preview.bmSize.cy);
  778. SelectObject(preview.hdc, hBitmapCapture);
  779. }
  780. fr.hdc = preview.hdc;
  781. draw_preview(hEditorWnd, &fr, &paper, preview.page);
  782. if(preview.pages_shown > 1)
  783. {
  784. if (!preview.hdc2)
  785. {
  786. preview.hdc2 = CreateCompatibleDC(hdc);
  787. hBitmapCapture = CreateCompatibleBitmap(hdc,
  788. preview.bmSize.cx,
  789. preview.bmSize.cy);
  790. SelectObject(preview.hdc2, hBitmapCapture);
  791. }
  792. fr.hdc = preview.hdc2;
  793. draw_preview(hEditorWnd, &fr, &fr.rcPage, preview.page + 1);
  794. }
  795. DeleteDC(fr.hdcTarget);
  796. ReleaseDC(hwndPreview, hdc);
  797. InvalidateRect(hwndPreview, NULL, FALSE);
  798. update_preview_buttons(hMainWnd);
  799. update_preview_statusbar(hMainWnd);
  800. }
  801. static void toggle_num_pages(HWND hMainWnd)
  802. {
  803. HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
  804. WCHAR name[MAX_STRING_LEN];
  805. HINSTANCE hInst = GetModuleHandleW(0);
  806. int nPreviewPages;
  807. preview.pages_shown = preview.pages_shown > 1 ? 1 : 2;
  808. nPreviewPages = preview.zoomlevel > 0 ? preview.saved_pages_shown :
  809. preview.pages_shown;
  810. LoadStringW(hInst, nPreviewPages > 1 ? STRING_PREVIEW_ONEPAGE :
  811. STRING_PREVIEW_TWOPAGES,
  812. name, MAX_STRING_LEN);
  813. SetWindowTextW(GetDlgItem(hReBar, ID_PREVIEW_NUMPAGES), name);
  814. update_preview_sizes(GetDlgItem(hMainWnd, IDC_PREVIEW), TRUE);
  815. update_preview(hMainWnd);
  816. }
  817. /* Returns the page shown that the point is in (1 or 2) or 0 if the point
  818. * isn't inside either page */
  819. static int preview_page_hittest(POINT pt)
  820. {
  821. RECT rc;
  822. rc.left = preview.spacing.cx;
  823. rc.right = rc.left + preview.bmScaledSize.cx;
  824. rc.top = preview.spacing.cy;
  825. rc.bottom = rc.top + preview.bmScaledSize.cy;
  826. if (PtInRect(&rc, pt))
  827. return 1;
  828. if (preview.pages_shown <= 1)
  829. return 0;
  830. rc.left += preview.bmScaledSize.cx + preview.spacing.cx;
  831. rc.right += preview.bmScaledSize.cx + preview.spacing.cx;
  832. if (PtInRect(&rc, pt))
  833. return is_last_preview_page(preview.page) ? 1 : 2;
  834. return 0;
  835. }
  836. LRESULT CALLBACK preview_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  837. {
  838. switch(msg)
  839. {
  840. case WM_CREATE:
  841. {
  842. HWND hMainWnd = GetParent(hWnd);
  843. HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
  844. FORMATRANGE fr;
  845. GETTEXTLENGTHEX gt = {GTL_DEFAULT, 1200};
  846. HDC hdc = GetDC(hWnd);
  847. HDC hdcTarget = make_dc();
  848. fr.rc = preview.rcPage = get_print_rect(hdcTarget);
  849. preview.rcPage.bottom += margins.bottom;
  850. preview.rcPage.right += margins.right;
  851. preview.rcPage.top = preview.rcPage.left = 0;
  852. fr.rcPage = preview.rcPage;
  853. preview.bmSize.cx = twips_to_pixels(preview.rcPage.right, GetDeviceCaps(hdc, LOGPIXELSX));
  854. preview.bmSize.cy = twips_to_pixels(preview.rcPage.bottom, GetDeviceCaps(hdc, LOGPIXELSY));
  855. preview.textlength = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0);
  856. fr.hdc = CreateCompatibleDC(hdc);
  857. fr.hdcTarget = hdcTarget;
  858. fr.chrg.cpMin = 0;
  859. fr.chrg.cpMax = preview.textlength;
  860. DeleteDC(fr.hdc);
  861. DeleteDC(hdcTarget);
  862. ReleaseDC(hWnd, hdc);
  863. update_preview_sizes(hWnd, TRUE);
  864. update_preview(hMainWnd);
  865. break;
  866. }
  867. case WM_PAINT:
  868. return print_preview(hWnd);
  869. case WM_SIZE:
  870. {
  871. update_preview_sizes(hWnd, FALSE);
  872. InvalidateRect(hWnd, NULL, FALSE);
  873. break;
  874. }
  875. case WM_VSCROLL:
  876. case WM_HSCROLL:
  877. {
  878. SCROLLINFO si;
  879. RECT rc;
  880. int nBar = (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ;
  881. int origPos;
  882. GetClientRect(hWnd, &rc);
  883. si.cbSize = sizeof(si);
  884. si.fMask = SIF_ALL;
  885. GetScrollInfo(hWnd, nBar, &si);
  886. origPos = si.nPos;
  887. switch(LOWORD(wParam))
  888. {
  889. case SB_TOP: /* == SB_LEFT */
  890. si.nPos = si.nMin;
  891. break;
  892. case SB_BOTTOM: /* == SB_RIGHT */
  893. si.nPos = si.nMax;
  894. break;
  895. case SB_LINEUP: /* == SB_LINELEFT */
  896. si.nPos -= si.nPage / 10;
  897. break;
  898. case SB_LINEDOWN: /* == SB_LINERIGHT */
  899. si.nPos += si.nPage / 10;
  900. break;
  901. case SB_PAGEUP: /* == SB_PAGELEFT */
  902. si.nPos -= si.nPage;
  903. break;
  904. case SB_PAGEDOWN: /* SB_PAGERIGHT */
  905. si.nPos += si.nPage;
  906. break;
  907. case SB_THUMBTRACK:
  908. si.nPos = si.nTrackPos;
  909. break;
  910. }
  911. si.fMask = SIF_POS;
  912. SetScrollInfo(hWnd, nBar, &si, TRUE);
  913. GetScrollInfo(hWnd, nBar, &si);
  914. if (si.nPos != origPos)
  915. {
  916. int amount = origPos - si.nPos;
  917. if (msg == WM_VSCROLL)
  918. ScrollWindow(hWnd, 0, amount, NULL, NULL);
  919. else
  920. ScrollWindow(hWnd, amount, 0, NULL, NULL);
  921. }
  922. return 0;
  923. }
  924. case WM_SETCURSOR:
  925. {
  926. POINT pt;
  927. RECT rc;
  928. int bHittest = 0;
  929. DWORD messagePos = GetMessagePos();
  930. pt.x = (short)LOWORD(messagePos);
  931. pt.y = (short)HIWORD(messagePos);
  932. ScreenToClient(hWnd, &pt);
  933. GetClientRect(hWnd, &rc);
  934. if (PtInRect(&rc, pt))
  935. {
  936. pt.x += GetScrollPos(hWnd, SB_HORZ);
  937. pt.y += GetScrollPos(hWnd, SB_VERT);
  938. bHittest = preview_page_hittest(pt);
  939. }
  940. if (bHittest)
  941. SetCursor(LoadCursorW(GetModuleHandleW(0),
  942. MAKEINTRESOURCEW(IDC_ZOOM)));
  943. else
  944. SetCursor(LoadCursorW(NULL, (WCHAR*)IDC_ARROW));
  945. return TRUE;
  946. }
  947. case WM_LBUTTONDOWN:
  948. {
  949. int page;
  950. POINT pt;
  951. pt.x = (short)LOWORD(lParam) + GetScrollPos(hWnd, SB_HORZ);
  952. pt.y = (short)HIWORD(lParam) + GetScrollPos(hWnd, SB_VERT);
  953. if ((page = preview_page_hittest(pt)) > 0)
  954. {
  955. HWND hMainWnd = GetParent(hWnd);
  956. /* Convert point from client coordinate to unzoomed page
  957. * coordinate. */
  958. pt.x -= preview.spacing.cx;
  959. if (page > 1)
  960. pt.x -= preview.bmScaledSize.cx + preview.spacing.cx;
  961. pt.y -= preview.spacing.cy;
  962. pt.x /= preview.zoomratio;
  963. pt.y /= preview.zoomratio;
  964. if (preview.zoomlevel == 0)
  965. preview.saved_pages_shown = preview.pages_shown;
  966. preview.zoomlevel = (preview.zoomlevel + 1) % 3;
  967. preview.zoomratio = 0;
  968. if (preview.zoomlevel == 0 && preview.saved_pages_shown > 1)
  969. {
  970. toggle_num_pages(hMainWnd);
  971. } else if (preview.pages_shown > 1) {
  972. if (page >= 2) preview.page++;
  973. toggle_num_pages(hMainWnd);
  974. } else {
  975. update_preview_sizes(hWnd, TRUE);
  976. InvalidateRect(hWnd, NULL, FALSE);
  977. update_preview_buttons(hMainWnd);
  978. }
  979. if (preview.zoomlevel > 0) {
  980. SCROLLINFO si;
  981. /* Convert the coordinate back to client coordinate. */
  982. pt.x *= preview.zoomratio;
  983. pt.y *= preview.zoomratio;
  984. pt.x += preview.spacing.cx;
  985. pt.y += preview.spacing.cy;
  986. /* Scroll to center view at that point on the page */
  987. si.cbSize = sizeof(si);
  988. si.fMask = SIF_PAGE;
  989. GetScrollInfo(hWnd, SB_HORZ, &si);
  990. pt.x -= si.nPage / 2;
  991. SetScrollPos(hWnd, SB_HORZ, pt.x, TRUE);
  992. GetScrollInfo(hWnd, SB_VERT, &si);
  993. pt.y -= si.nPage / 2;
  994. SetScrollPos(hWnd, SB_VERT, pt.y, TRUE);
  995. }
  996. }
  997. }
  998. default:
  999. return DefWindowProcW(hWnd, msg, wParam, lParam);
  1000. }
  1001. return 0;
  1002. }
  1003. LRESULT preview_command(HWND hWnd, WPARAM wParam)
  1004. {
  1005. switch(LOWORD(wParam))
  1006. {
  1007. case ID_FILE_EXIT:
  1008. PostMessageW(hWnd, WM_CLOSE, 0, 0);
  1009. break;
  1010. case ID_PREVIEW_NEXTPAGE:
  1011. case ID_PREVIEW_PREVPAGE:
  1012. {
  1013. if(LOWORD(wParam) == ID_PREVIEW_NEXTPAGE)
  1014. preview.page++;
  1015. else
  1016. preview.page--;
  1017. update_preview(hWnd);
  1018. }
  1019. break;
  1020. case ID_PREVIEW_NUMPAGES:
  1021. toggle_num_pages(hWnd);
  1022. break;
  1023. case ID_PREVIEW_ZOOMIN:
  1024. if (preview.zoomlevel < 2)
  1025. {
  1026. if (preview.zoomlevel == 0)
  1027. preview.saved_pages_shown = preview.pages_shown;
  1028. preview.zoomlevel++;
  1029. preview.zoomratio = 0;
  1030. if (preview.pages_shown > 1)
  1031. {
  1032. /* Forced switch to one page when zooming in. */
  1033. toggle_num_pages(hWnd);
  1034. } else {
  1035. HWND hwndPreview = GetDlgItem(hWnd, IDC_PREVIEW);
  1036. update_preview_sizes(hwndPreview, TRUE);
  1037. InvalidateRect(hwndPreview, NULL, FALSE);
  1038. update_preview_buttons(hWnd);
  1039. }
  1040. }
  1041. break;
  1042. case ID_PREVIEW_ZOOMOUT:
  1043. if (preview.zoomlevel > 0)
  1044. {
  1045. HWND hwndPreview = GetDlgItem(hWnd, IDC_PREVIEW);
  1046. preview.zoomlevel--;
  1047. preview.zoomratio = 0;
  1048. if (preview.zoomlevel == 0 && preview.saved_pages_shown > 1) {
  1049. toggle_num_pages(hWnd);
  1050. } else {
  1051. update_preview_sizes(hwndPreview, TRUE);
  1052. InvalidateRect(hwndPreview, NULL, FALSE);
  1053. update_preview_buttons(hWnd);
  1054. }
  1055. }
  1056. break;
  1057. case ID_PRINT:
  1058. dialog_print(hWnd, preview.wszFileName);
  1059. SendMessageW(hWnd, WM_CLOSE, 0, 0);
  1060. break;
  1061. }
  1062. return 0;
  1063. }