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